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

?个人简介

⭐️个人主页:摸鱼の文酱博客主页?‍♂️
?博客领域: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_AcostA来进行排序,那么当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_APersonXcostA<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_BPersonXcostB>>PersonYcostB时,我们选择P e r s o n X 去 C i t y A Person X去City APersonXCityA,那么很明显总和会更大,同理c o s t A cost_AcostA也不能。
那么以哪个值来进行排序呢?
假如让2 ∗ n 2*n2n个人都去c i t y B city BcityB, 然后在其中选择n nn个人去c i t y A city AcityA,那么这些人公司需要额外付p r i c e A − p r i c e B price_A - price_BpriceApriceB.
最后我们得到了答案,那就是根据p r i c e A − p r i c e B price_A - price_BpriceApriceB来进行排序,前n nn个人去c i t y A city AcityA, 后面的去c i t y B city BcityB

    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];
    }
}

版权声明:本文为qq_53947552原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。