贪心 -力扣860.柠檬水找零力扣2208.将数组和减半的最少操作次数力扣179.最大数力扣376.摆动序列

简介: 贪心 -力扣860.柠檬水找零力扣2208.将数组和减半的最少操作次数力扣179.最大数力扣376.摆动序列

贪心策略,局部最优->全局最优

1.把解决问题的过程分为若干步骤

2.解决每一步的时候,都选择当前看起来“最优秀的”解法

3.希望能够得到全局最优解

例子1:找零问题 50-4=46  ->[20,10,5,1] 46->26->6->5->1   找当前能够找到的最大解法。

例子2:最小路径和(当初动态规划)

每次只能向下,或者向右侧,找到最小的路径,                                                                              11611,这个不一定对,但是符合贪心的策略,鼠目寸光

例子三:背包问题

疯狂装体积小的,直接塞满(只去考虑体积,考虑价值,则去疯狂交给价值)

1.贪心策略的特点:

1.贪心策略的提出是没有标准和模版的

2.可能每一道贪心策略都是不同的

2.贪心策略的正确性

贪心策略可能是一个错误的方法,正确的贪心,是需要一个证明的

常用的证明方法:数学中见过的所有方法

找零问题:【20,10,5,1】

力扣860.柠檬水找零

class Solution {
    public boolean lemonadeChange(int[] bills) {
if(bills[0]>5){
    return false;
}
//找钱也就是15块和5块
int five=0;int ten=0;
for(int i=0;i<bills.length;i++){
    if(bills[i]==5){
        five++;
    }else if(bills[i]==10){
        ten++;
        five--;
    }
    else if(bills[i]==20){
        if(ten>0){
        ten--;
        five--;
        }else{
       five=five-3;
        }
    }
     if(five<0||ten<0){
    return false;
}
 
}
 
return true;
    }
}

力扣2208.将数组和减半的最少操作次数

class Solution {
    //贪心,每次都去挑选数组中最大的数,然后减半,知道数组和到原来的一半
    public int halveArray(int[] nums) {
  
    int count=0;
    //每次都挑选最大的数,借助一个数据结构(大根堆)
//拿到堆顶,然后再去/2放到大根堆里面
 PriorityQueue <Double>priorityQueue=new PriorityQueue<>((a,b)->b.compareTo(a));
   double sum=0;
    for(double num:nums){
        priorityQueue.add(num);
        sum+=num;
    }
    sum=sum/2.0;
while(sum>0){
    double p=priorityQueue.poll()/2.0;
    count++;
    sum=sum-p;
    priorityQueue.add(p);
}
return count;
 
    }
}

力扣179.最大数

正常的排序:确定元素的先后顺序:谁在前面,谁在后面

a和b是同一数量级,比如 8,9 或者10,11或者34, 36。我的意思是,两位数和两位数比,一位数和一位数比

a和b不是统一数量级,假如位数不一样,那么就依次循环,来确定首尾

谈谈这块,首先这个sort的使用比较器的方法,只适用于包装类的逆序,并不适用于基础类型

      Integer []nums={1,2,3,4};
            //排序
            Arrays.sort(nums,Comparator.reverseOrder());
            for(int x:nums){
                System.out.println(x);
            }


在Java中,当你尝试对字符串数组使用Lambda表达式进行排序,并且使用(b+a).compareTo(a+b)作为比较逻辑时,b+a和a+b在大多数情况下看起来可能相同,因为它们都是将两个字符串拼接起来。但是,这里的关键在于这两个表达式在特定的字符串上可能会产生不同的结果,特别是当涉及到字符串连接时的数值解释时。

考虑以下情况:

当a和b都是数字字符串时(例如a="12",b="3"),b+a和a+b拼接后的字符串在数值上可能不同,但它们在字典顺序上可能是相同的。例如,"312"和"123"作为字符串在字典顺序上是不同的。

当a和b中包含非数字字符时,拼接后的结果将完全基于字符串的字典顺序,而不是任何潜在的数值解释。

现在,让我们详细分析(b+a).compareTo(a+b)的比较逻辑:

如果b+a在字典顺序上位于a+b之前,则compareTo方法将返回一个负数,表示b应该在a之前。

如果b+a和a+b在字典顺序上相同,则compareTo方法将返回0,表示a和b的位置不变。

如果b+a在字典顺序上位于a+b之后,则compareTo方法将返回一个正数,表示b应该在a之后。

这种比较逻辑在某些特定情况下可能看起来有些奇怪,特别是当处理数字字符串时。通常,如果你想要按照数值对数字字符串进行排序,你应该先将它们转换为数值类型(如Integer或Long),然后再进行比较。

然而,在你提供的例子中,这种比较逻辑可能用于创建一种特定的排序顺序,该顺序可能基于字符串的某种非直观或特殊的比较逻辑。

最后,值得注意的是,对于非数字字符串,这种比较逻辑可能不会产生有意义的结果,因为字符串的字典顺序和它们的任何潜在数值解释之间可能没有直接关系。

其实不用记住顺序,尝试一遍不就好咯。

class Solution {
    public String largestNumber(int[] nums) {
    int n=nums.length;
    String[] strs=new String[n];
    for(int i=0;i<n;i++) strs[i]=""+nums[i];
    //排序
    Arrays.sort(strs,(a,b)->
    {
       return (b+a).compareTo(a+b);
    });
//提取结果
StringBuffer ret=new StringBuffer();
for(String s:strs) ret.append(s);
if(ret.charAt(0)=='0')return "0";
return ret.toString();
    }
}

只有符合全序关系,才能说明贪心正确。

证明 ab,ba两个拼接起来都是数,能够比较大小,就算是字符串也是可以比较ac码,所以可以视为数字。

力扣376.摆动序列

class Solution {
    public  static int wiggleMaxLength(int[] nums) {
        int n=nums.length;
            if(n<2){
                return n;
            }
            int left=0;
            int ret=0;
            int right=0;
            for(int i=0;i<n-1;i++){
 
                right=nums[i+1]-nums[i];
                if(right==0){
                    continue;
                }
                //y要么是波峰, 要么是波谷
                //第一个点也考虑进去,注意等于0的情况是第一个点,假如第一个点不是0,那么left*right也不会等于0,因为假如right=0,那么就会跳过了
                if(left*right<=0){
                    ret++;
                }
                left=right;
            }
            return ret+1;
        }
        
}


相关文章
|
1月前
|
算法
Leetcode 初级算法 --- 数组篇
Leetcode 初级算法 --- 数组篇
38 0
|
3月前
|
算法
LeetCode第53题最大子数组和
LeetCode第53题"最大子数组和"的解题方法,利用动态规划思想,通过一次遍历数组,维护到当前元素为止的最大子数组和,有效避免了复杂度更高的暴力解法。
LeetCode第53题最大子数组和
|
3月前
|
存储 Java API
LeetCode------合并两个有序数组(4)【数组】
这篇文章介绍了LeetCode上的"合并两个有序数组"问题,并提供了三种解法:第一种是使用Java的Arrays.sort()方法直接对合并后的数组进行排序;第二种是使用辅助数组和双指针技术进行合并;第三种则是从后向前的双指针方法,避免了使用额外的辅助数组。
LeetCode------合并两个有序数组(4)【数组】
|
3月前
|
搜索推荐 索引 Python
【Leetcode刷题Python】牛客. 数组中未出现的最小正整数
本文介绍了牛客网题目"数组中未出现的最小正整数"的解法,提供了一种满足O(n)时间复杂度和O(1)空间复杂度要求的原地排序算法,并给出了Python实现代码。
113 2
LeetCode------找到所有数组中消失的数字(6)【数组】
这篇文章介绍了LeetCode上的"找到所有数组中消失的数字"问题,提供了一种解法,通过两次遍历来找出所有未在数组中出现的数字:第一次遍历将数组中的每个数字对应位置的值增加数组长度,第二次遍历找出所有未被增加的数字,即缺失的数字。
|
3月前
|
前端开发
LeetCode------移动零(5)【数组】
这篇文章介绍了LeetCode上的"移动零"问题,提出了一种使用双指针的原地操作解法,该方法首先将非零元素移动到数组前端并保持相对顺序,然后填充后续位置为零,以达到题目要求。
|
1月前
【LeetCode-每日一题】 删除排序数组中的重复项
【LeetCode-每日一题】 删除排序数组中的重复项
19 4
|
1月前
|
索引
Leetcode第三十三题(搜索旋转排序数组)
这篇文章介绍了解决LeetCode第33题“搜索旋转排序数组”的方法,该问题要求在旋转过的升序数组中找到给定目标值的索引,如果存在则返回索引,否则返回-1,文章提供了一个时间复杂度为O(logn)的二分搜索算法实现。
18 0
Leetcode第三十三题(搜索旋转排序数组)
|
1月前
|
算法 C++
Leetcode第53题(最大子数组和)
这篇文章介绍了LeetCode第53题“最大子数组和”的动态规划解法,提供了详细的状态转移方程和C++代码实现,并讨论了其他算法如贪心、分治、改进动态规划和分块累计法。
56 0
|
1月前
|
C++
【LeetCode 12】349.两个数组的交集
【LeetCode 12】349.两个数组的交集
16 0