0
点赞
收藏
分享

微信扫一扫

代码随想录之贪心系列两个维度权衡问题算法

兮城 2022-05-04 阅读 51

文章目录

代码随想录之贪心系列两个维度权衡问题算法

1.分发糖果

1.1贪心算法

func candy(ratings []int) int {
    /**先确定一边,再确定另外一边
        1.先从左到右,当右边的大于左边的就加1
        2.再从右到左,当左边的大于右边的就再加1
    **/
    need:=make([]int,len(ratings))
    sum:=0
    //初始化(每个人至少一个糖果);每个孩子至少分配到 1 个糖果
     for i:=0;i<len(ratings);i++{
         need[i]=1
     }
     //1.先从左到右,当右边的大于左边的就加1
    //不对最后一个孩子进行遍历,因为最后一个元素没有右边孩子,而且下面有[i+1]
    //只做如下判断还够不够,假如说是[1,3,2],第三个元素小于第二个元素,也就是说不会对第二个元素
    for i:=1;i<len(ratings);i++{
        //对孩子评分进行比较
        if ratings[i-1]<ratings[i]{
            need[i]=need[i-1]+1
        }
    }
    //2.再从右到左,当左边的大于右边的就右边加1,但要花费糖果最少,所以需要做下判断
    for i:=len(ratings)-2;i>=0;i--{
        if ratings[i]>ratings[i+1]{
            //need[i+1]+1是右边加1的到的数量;
            need[i]=findMax(need[i],need[i+1]+1)
        }
    }
    //计算总共糖果
    for i:=0;i<len(ratings);i++{
        sum+=need[i]
    }
    return sum
}
func findMax(num1 int ,num2 int) int{
    if num1>num2{
        return num1
    }
    return num2
}
//题意思:当输入[1,3,2]时输出4,即分别分发1,2,1个糖果
当输入[1.2,3]时,输出6

image-20220308112644965

比较右边评分比左边大的贪心:

image-20220308114611400

比较左边评分比右边大的贪心:

image-20220308124947869

image-20220308124747226

image-20220308123742835

image-20220308112452288

2.根据身高重建队列

2.1贪心算法

func reconstructQueue(people [][]int) [][]int {
	//先将身高从大到小排序,确定最大个子的相对位置
	sort.Slice(people,func(i,j int)bool{
		if people[i][0]==people[j][0]{
			return people[i][1]<people[j][1]//这个才是当身高相同时,将K按照从小到大排序
		}
		//这个只是确保身高按照由大到小的顺序来排,并不确定K是按照从小到大排序的
		return people[i][0]>people[j][0]
	})
	//再按照K进行插入排序,优先插入K小的
	result := make([][]int, 0)
	for _, info := range people {
		if len(result) <= info[1] {
			result = append(result, info)
		}else {
			result = append(result, []int{0,0})//用于扩展一个空间
			copy(result[info[1]+1:], result[info[1]:]) //将插入位置之后的元素后移动一位(意思是腾出空间)
			result[info[1]] = info                     //将插入元素位置插入元素
		}}
	return result
}
//思路:
分析:
本题有两个维度,h和k,看到这种题目一定要想如何确定一个维度,然后在按照另一个维度重新排列。
其实与分发糖果此题有点点的像,遇到两个维度权衡的时候,一定要先确定一个维度,再确定另一个维度,如果两个维度一起考虑一定会顾此失彼;


第一步:确定维度(即先排序)
先确定k还是先确定h呢,也就是究竟先按k个数排序呢,还先按照h身高排序呢?
*如果按人数k排序的话,拍完之后,会发现k的排列并不符合条件,身高也不符合条件,两个维度哪一个都没确定下来
*如果按身高h排序的话,身高一定是从大到小排(身高相同的话则k小的站前面),此时我们可以确定一个维度了,就是身高,前面的节点一定都比本节点高!
[[7,0],[4,4],[7,1],[5,0],[6,1],[5,2]]排序后是[[7,0],[7,1],[6,1],[5,0],[5,2],[4,4]]
第二步:再插队
在本题目中,我首先对数对进行排序,按照数对的元素 1 降序排序,按照数对的元素 2 升序排序。原因是,按照元素 1 进行降序排序,对于每个元素,在其之前的元素的个数,就是大于等于他的元素的数量,而按照第二个元素正向排序,我们希望 k 大的尽量在后面,减少插入操作的次数。
这就是本题的贪心思想所在,局部最优:优先按身高高的人的个数k来插入,插入操作过后的数组满足题目要求属性
全局最优:最后都做完插入操作,整个队列满足题目队列属性
 
套路:
一般这种数对,还涉及排序的,根据第一个元素正向排序,根据第二个元素反向排序,或者根据第一个元素反向排序,根据第二个元素正向排序,往往能够简化解题过程。

img

img

img

img

img

img

img

img

img

image-20220308125535245

举报

相关推荐

0 条评论