【算法修炼】贪心

贪心算法或贪心思想采用贪心的策略,保证每次操作都是局部最优的,从而使最后得到的结果是全局最优的。

贪心从某种意义上来讲,它不是一种算法,是一种思维,真正解决问题的是贪心思维加上其它的算法(排序、手动模拟、数据结构、搜索等),下面即将开启贪心的学习,并配合几套题目的练习。

分发饼干(简单)(排序+贪心)

在这里插入图片描述
把饼干和小孩的胃口值分别升序排序,用较小尺寸的饼干去满足较小胃口值的小孩。

import java.util.Arrays;
class Solution {
    public int findContentChildren(int[] g, int[] s) {
        Arrays.sort(g);
        Arrays.sort(s);
        int res = 0;
        int i = 0, j = 0;
        while (i < g.length && j < s.length) {
            if (g[i] <= s[j]) {
                res++;
                i++;
                j++;
            }else {
                j++;
                continue;
            }
        }
        return res;
    }
}

分发糖果(困难)(贪心)

在这里插入图片描述
这道题还是没搞明白为什么,先把题解放着吧。
在这里插入图片描述
代码:

class Solution {
    public int candy(int[] ratings) {
        int n = ratings.length;
        int[] left = new int[n];
        for (int i = 0; i < n; i++) {
            if (i > 0 && ratings[i] > ratings[i - 1]) {
                left[i] = left[i - 1] + 1;
            } else {
                left[i] = 1;
            }
        }
        int right = 0, ret = 0;
        for (int i = n - 1; i >= 0; i--) {
            if (i < n - 1 && ratings[i] > ratings[i + 1]) {
                right++;
            } else {
                right = 1;
            }
            ret += Math.max(left[i], right);
        }
        return ret;
    }
}

最长回文串(简单)

在这里插入图片描述
注意区分大小写,一看到回文题目要知道回文串里的每个字符,最多只有一个字符出现奇数次,其余都是偶数次。

class Solution {
    public int longestPalindrome(String s) {
        // 先统计已有字符串中的字符个数(区分大小写)
        int[] hash = new int[128];
        for(int i = 0; i < s.length(); i++) {
            hash[s.charAt(i)]++;
        }
        // 统计最长回文长度
        int ans = 0;
        // 注意回文串中最多有一个奇数字符(作为中间字符),其余字符都为偶数
        for(int i = 0; i < 128; i++) {
            // 整数除 2,不论奇偶个数字符都是取偶数个,乘 2是因为左右对称,各有一半
            ans += (hash[i] / 2) * 2;
            if (hash[i] % 2 == 1 && ans % 2 == 0) {
                ans++;
            }
        }
        return ans;
    }
}

数组拆分Ⅰ(简单)

在这里插入图片描述
数组从小到大排序后,累加第1 3 5 7 …位数。

class Solution {
    public int arrayPairSum(int[] nums) {
        Arrays.sort(nums);
        int ans = 0;
        int i = 0;
        while (i < nums.length) {
            ans += nums[i];
            i += 2;
        }
        return ans;
    }
}

验证回文字符串Ⅱ(简单)

在这里插入图片描述
双指针一前一后遍历字符串,如果遇到不同的字符就试试去除前面的字符或后面的字符,去除后再判断是否为回文串。

class Solution {
    public boolean validPalindrome(String s) {
        int i = 0, j = s.length() - 1;
        while (i < j) {
            // i == j 时不用判断
            if (s.charAt(i) == s.charAt(j)) {
                i++;
                j--;
            }else {
                return check(i+1, j, s) || check(i, j-1, s);
            }
        }
        return true;
    }
    static boolean check(int i, int j, String s) {
        while (i < j) {
            if (s.charAt(i) == s.charAt(j)) {
                i++;
                j--;
            }else {
                return false;
            }
        }
        return true;
    }
}

柠檬水找零(简单)

在这里插入图片描述
在付20美元时,需要找回15美元,优先用10美元的去找,然后再用5美元,因为5美元的可用性更高。

class Solution {
    public boolean lemonadeChange(int[] bills) {
        int[] price = new int[30];
        for (int i = 0; i < bills.length; i++) {
            int tmp = bills[i];
            if (tmp == 5) {
                price[tmp]++;
            }else if (tmp == 10) {
                if (price[5] > 0) {
                    price[5]--;
                    price[tmp]++;
                }else {
                    return false;
                }
            }else {
                // tmp == 20,先用10块钱的去找零,5块钱更灵动
                if (price[10] >= 1 && price[5] >= 1) {
                    price[tmp]++;
                    price[10]--;
                    price[5]--;
                }else if(price[5] >= 3) {
                    price[tmp]++;
                    price[5] -= 3;
                }else {
                    return false;
                }
            }
        }
        return true;
    }
}

在这里插入图片描述
看示例就能得到规律:I从0开始放,D从N开始放,最后判别最后一个字符是什么字符再确定数组最后一个元素。

class Solution {
    public int[] diStringMatch(String s) {
        int len = s.length();
        // 仔细看示例就能看出规律
        int left = 0;
        int right = len;
        int[] ans = new int[len + 1];
        for (int i = 0; i < len; i++) {
            if (s.charAt(i) == 'I') {
                ans[i] = left;
                left++;
            }else {
                ans[i] = right;
                right--;
            }
        }
        if (s.charAt(len - 1) == 'I') {
            ans[len] = ans[len - 1] + 1;
        }else {
            ans[len] = ans[len - 1] - 1;
        }
        return ans;
    }
}

将数组分成和相等的三个部分(简单)

在这里插入图片描述
整个数组的和应该能被3整除,每一部分是连续的。

class Solution {
    public boolean canThreePartsEqualSum(int[] arr) {
        // 整个数组的和必须要能被 3 整除
        // 是连续的三个部分
        int sum = 0;
        for (int i = 0; i < arr.length; i++) {
            sum += arr[i];
        }
        if (sum % 3 != 0) {
            return false;
        }
        sum = sum / 3;
        int cnt = 0;
        int i = 0;
        int tmp = 0;
        while (i < arr.length) {
            tmp += arr[i];
            if (tmp == sum) {
                cnt++;
                tmp = 0;
            }
            if (cnt == 3) {
                return true;
            }
            i++;
        }
        return false;
    }
}

玩筹码(简单)

在这里插入图片描述
偶数位置可以0代价放到位置0,奇数位置可以0代价放到位置1,再比较0、1筹码个数,把个数少的移到多的身上去,代价为筹码数 * 1。

class Solution {
    public int minCostToMoveChips(int[] position) {
        // 偶数位置筹码都放到 第 0 个位置
        // 奇数位置筹码都放到 第 1 个位置(因为左右移2个单位,代价为 0 )
        int z = 0;
        int f = 0;
        // 注意position记录一个个筹码的位置
        for (int i = 0; i < position.length; i++) {
            if (position[i] % 2 == 0) {
                z++;
            } else {
                f++;
            }
        }
        return z > f ? f : z;
    }
}

分割平衡字符串(简单)

在这里插入图片描述
维护一个变量cnt,遇到R就加1,遇到L就减1,如果cnt=0说明有字符串成立了,答案+1。(重要的是贪心的思维、思路,代码实现都很简单)

class Solution {
    public int balancedStringSplit(String s) {
        int cnt = 0;
        int all = 0;
        for (int i = 0; i < s.length(); i++) {
            if (s.charAt(i) == 'R') {
                cnt++;
            }else {
                cnt--;
            }
            if (cnt == 0) {
                all++;
            }
        }
        return all;
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

@u@

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值