算法刷题集训第四天--贪心

📜个人简介

⭐️个人主页:摸鱼の文酱博客主页🙋‍♂️
🍑博客领域:java编程基础,mysql
🍅写作风格:干货,干货,还是tmd的干货
🌸精选专栏:【Java】【mysql】 【算法刷题笔记】
🎯博主的码云gitee,平常博主写的程序代码都在里面。
🚀支持博主:点赞👍、收藏⭐、留言💬
🍭作者水平很有限,如果发现错误,一定要及时告知作者哦!感谢感谢!

题目链接难度
1464. 数组中两元素的最大乘积easy
1217. 玩筹码easy
1029. 两地调度medium
面试题 10.11. 峰与谷medium

📃1464. 数组中两元素的最大乘积

🎯解题思路

📒思路一:暴力

  分别计数L和R的次数,每当两个出现次数相同时分割一次,同时再把L和R数量置为0

public static int balancedStringSplit(String s) {
        int R_count = 0;
        int L_count = 0;
        int count = 0;
        for (int i = 0; i < s.length(); i++) {
            if(s.charAt(i) == 'R'){
                R_count++;
            } else {
                L_count++;
            }
            if(R == L){
                count++;
                R_count=0;
                L_count=0;
            }
        }
        return count;
    }

📒思路二:贪心

  根据题意,对于一个平衡字符串 s,若 s 能从中间某处分割成左右两个子串,若其中一个是平衡字符串,则另一个的L 和R 字符的数量必然是相同的,所以也一定是平衡字符串。
为了最大化分割数量,我们可以不断循环,每次从 s 中分割出一个最短的平衡前缀,由于剩余部分也是平衡字符串,我们可以将其当作 s 继续分割,直至 s 为空时,结束循环。
代码实现中,可以在遍历 s 时用一个变量 d 维护L 和 R 字符的数量之差,当 d=0 时就说明找到了一个平衡字符串,将答案加一。

class Solution {
    public int balancedStringSplit(String s) {
        int ans = 0, d = 0;
        for (int i = 0; i < s.length(); ++i) {
            char ch = s.charAt(i);
            if (ch == 'L') {
                ++d;
            } else {
                --d;
            }
            if (d == 0) {
                ++ans;
            }
        }
        return ans;
    }
}

📃1217. 玩筹码

🎯解题思路

📒思路一:贪心

  1. 偶数变偶数,奇数变奇数,没有代价
  2. 偶数变奇数,奇数变偶数,代价为1
统计奇数和偶数的数量,取奇数和偶数数量较小的那个数量便是所求的代价。

/*
贪心策略(思路)
1.尽量多用代价为0的方式移动,将所有筹码移动到最接近,然后在用代价为1的方式移动筹码,知道筹码位置相同
2.由1可知如果最终位置为奇数,则原本奇数位置移动的代价为0,偶数位置移动的代价为1
  如果最终位置为偶数,则原本偶数位置移动的代价为0,奇数位置移动的代价为1
3.【先统计奇数位置和偶数位置元素的个数,哪个少代价就是多少】
*/

class Solution {
    public int minCostToMoveChips(int[] position) {
        int[] num = new int[2];  //记录奇数和偶数的个数
        for (int i = 0; i < position.length; i++) {
            if (position[i] % 2==0){
                num[0]++;
            }else {
                num[1]++;
            }
        }
        return Math.min(num[0],num[1]);   //返回较小的数
    }
}

📃1029. 两地调度

🎯解题思路

📒思路一:贪心

  首先就需要对数组进行排序,但是如何排序?以哪个值来排序呢?
如果我们以 c o s t A cost_A costA来进行排序,那么当 P e r s o n X c o s t A < P e r s o n Y c o s t A Person X cost_A < Person Y cost_A PersonXcostA<PersonYcostA,同时 P e r s o n X c o s t B > > P e r s o n Y c o s t B Person X cost_B >> Person Y cost_B PersonXcostB>>PersonYcostB时,我们选择 P e r s o n X 去 C i t y A Person X去City A PersonXCityA,那么很明显总和会更大,同理 c o s t A cost_A costA也不能。
  那么以哪个值来进行排序呢?
假如让 2 ∗ n 2*n 2n个人都去 c i t y B city B cityB, 然后在其中选择 n n n个人去 c i t y A city A cityA,那么这些人公司需要额外付 p r i c e A − p r i c e B price_A - price_B priceApriceB.
最后我们得到了答案,那就是根据 p r i c e A − p r i c e B price_A - price_B priceApriceB来进行排序,前 n n n个人去 c i t y A city A cityA, 后面的去 c i t y B city B cityB

    public static int twoCitySchedCost(int[][] costs) {
        int len = costs.length;
        int[][] diff = new int[len][2];
        for (int i = 0; i < len; i++) {
            diff[i][0] = i;
            diff[i][1] = costs[i][0] - costs[i][1];
        }

        Arrays.sort(diff, (o1, o2) -> {
            if (o1[1] == o2[1]) {
                return o1[0] - o2[0];
            }
            return o1[1] - o2[1];
        });

        int ans = 0;
        for (int i = 0; i < len / 2; i++) {
            ans += costs[diff[i][0]][0];
        }

        for (int i = len / 2; i < len; i++) {
            ans += costs[diff[i][0]][1];
        }

        return ans;
    }

//优化
    public static int twoCitySchedCost_opt(int[][] costs) {
        Arrays.sort(costs, new Comparator<int[]>() {
            @Override
            public int compare(int[] o1, int[] o2) {
                return o1[0] - o1[1] - (o2[0] - o2[1]);
            }
        });

        int len = costs.length;
        int n = len / 2;
        int sum = 0;
        for (int i = 0; i < n; i++) {
            sum += costs[i][0] + costs[i + n][1];
        }

        return sum;
    }

📒思路二:DP

    public static int twoCitySchedCost_dp(int[][] costs) {
        int n = costs.length / 2;
        int[][] dp = new int[n + 1][n + 1];
        for (int i = 1; i <= n; i++) {
            dp[i][0] = dp[i - 1][0] + costs[i - 1][0];
            dp[0][i] = dp[0][i - 1] + costs[i - 1][1];
        }

        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= n; j++) {
                dp[i][j] = Math.min(dp[i - 1][j] + costs[i + j - 1][0], dp[i][j - 1] + costs[i + j - 1][1]);
            }
        }

        return dp[n][n];
    }

📒思路三:递归

    public static int twoCitySchedCost_rec(int[][] costs) {
        int n = costs.length / 2;
        int[][] dp = new int[2 * n][2 * n];
        return helper(dp, costs, 0, 0);
    }

    public static int helper(int[][] dp, int[][] costs, int idx, int cityA) {
        if (idx == costs.length) {
            return 0;
        }

        if (dp[idx][cityA] > 0) {
            return dp[idx][cityA];
        }

        int n = costs.length / 2;
        // n persons arrived to second city
        if (idx - cityA == n) {
            return dp[idx][cityA] = costs[idx][0] + helper(dp, costs, idx + 1, cityA + 1);
        } else if (cityA == n) { // n persons arrived to first city
            return dp[idx][cityA] = costs[idx][1] + helper(dp, costs, idx + 1, cityA);
        } else {
            return dp[idx][cityA] = Math.min(costs[idx][1] + helper(dp, costs, idx + 1, cityA), costs[idx][0] + helper(dp, costs, idx + 1, cityA + 1));
        }
    }

📃面试题 10.11. 峰与谷

🎯解题思路

📒思路一:排序

  首先就对数组进行排序,将排序后的数组按照一个最大值后接一个最小值分配

class Solution {
    public void wiggleSort(int[] nums) {
        int idx = 0, len = nums.length;
        if (len < 3) return;
        int low = 0, high = len - 1;
        int[] sorted = Arrays.copyOf(nums, len);
        Arrays.sort(sorted);
        while (low < high) {
            nums[idx++] = sorted[high--];
            nums[idx++] = sorted[low++];
        }
        if (len % 2 > 0)
            nums[idx] = sorted[low];
    }
}

📒思路二:遍历

  遍历数组,保证数组在局部为谷-峰-谷

class Solution {
    public void wiggleSort(int[] nums) {
        int n = nums.length;
        for (int i = 1; i < n; ++i)
            if ((i & 1) == 1 ? nums[i] < nums[i - 1] : nums[i] > nums[i - 1])
                swap(nums, i, i - 1);
    }

    private void swap(int[] nums, int idx1, int idx2) {
        nums[idx1] ^= nums[idx2];
        nums[idx2] ^= nums[idx1];
        nums[idx1] ^= nums[idx2];
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值