左程云大厂算法刷题班——12

第一题

leetcode296. 最佳的碰头地点
请添加图片描述

public class 第一题12 {
    public static void main(String[] args) {
        int[][] grid = {{1,1,0,1},{1,1,0,0},{1,0,0,0},{1,1,1,1}};
        int res = minTotalDistance(grid);
        System.out.println(res);
    }
    public static int minTotalDistance(int[][] grid){
        int n = grid.length;
        int m = grid[0].length;
        int[] rowOnes = new int[n];
        int[] colOnes = new int[m];
        for (int i = 0;i < n;i++){
            for (int j = 0;j < m;j++){
                if (grid[i][j] == 1){
                    rowOnes[i]++;
                    colOnes[j]++;
                }
            }
        }
        int total = 0;
        int up_row = 0;
        int down_row = 0;
        int up = 0;
        int down = n - 1;
        while (up < down){
            if (rowOnes[up] + up_row < rowOnes[down] + down_row){
                total += rowOnes[up] + up_row;
                up_row += rowOnes[up++];
            }else {
                total += rowOnes[down] + down_row;
                down_row += rowOnes[down--];
            }
        }
        int left_col = 0;
        int right_col = 0;
        int left = 0;
        int right = m - 1;
        while (left < right){
            if (colOnes[left] + left_col < rowOnes[right] + right_col){
                total += colOnes[left] + left_col;
                left_col += colOnes[left++];
            }else {
                total += colOnes[right] + right_col;
                right_col += colOnes[right--];
            }
        }
        return total;
    }
}

在这里插入图片描述
思路:
1.递归——》记忆化搜索
2.贪心 + 后缀和 + 二分(在sum非常大时,记忆化搜索效果很差)

public class 第二题12 {
    public static void main(String[] args) {
        int[] arr = {3,4,1,5,3,4,6,7,3,6,1,3,4,6,9,3,2};
        int res1 = minOpSteps1(arr, 2, 5);
        System.out.println(res1);
        int res2 = minOpSteps2(arr, 2, 5);
        System.out.println(res2);
        int res3 = minOpSteps3(arr, 2, 5);
        System.out.println(res3);
    }
    //暴力递归
    public static int minOpSteps1(int[] arr,int x,int y){
        int sum = 0;
        for (int i = 0;i < arr.length;i++){
            sum += arr[i];
        }
        return process1(arr,x,y,0,sum);
    }
    private static int process1(int[] arr, int x, int y, int index, int sum) {
        if (sum <= 0){
            return 0;
        }
        if (index == arr.length){
            return Integer.MAX_VALUE;
        }
        int p1 = process1(arr,x,y,index + 1,sum);//第一种情况:什么也不做

        int p2 = Integer.MAX_VALUE;//第二种情况:执行 x 操作
        int next_p2 = process1(arr,x,y,index + 1,sum - arr[index]);
        if (next_p2 != Integer.MAX_VALUE){
            p2 = next_p2 + x;
        }

        int p3 = Integer.MAX_VALUE;//第三种情况:执行y操作
        int next_p3 = process1(arr,x,y,index + 1,sum - 2 * arr[index]);
        if (next_p3 != Integer.MAX_VALUE){
            p3 = y + next_p3;
        }
        return Math.min(p1,Math.min(p2,p3));
    }
    //记忆化搜索
    public static int minOpSteps2(int[] arr,int x,int y){
        int sum = 0;
        for (int i = 0;i < arr.length;i++){
            sum += arr[i];
        }
        int[][] dp = new int[arr.length + 1][sum + 1];
        for (int i = 0;i <= arr.length;i++){
            for (int j = 0;j <= sum;j++){
                dp[i][j] = -1;
            }
        }
        return process2(arr,x,y,0,sum,dp);
    }
    private static int process2(int[] arr, int x, int y, int index, int sum, int[][] dp) {
        if (sum <= 0){
            return 0;
        }
        if (index == arr.length){
            return Integer.MAX_VALUE;
        }
        if (dp[index][sum] != -1){
            return dp[index][sum];
        }
        int p1 = process2(arr,x,y,index + 1,sum, dp);//第一种情况:什么也不做

        int p2 = Integer.MAX_VALUE;//第二种情况:执行 x 操作
        int next_p2 = process2(arr,x,y,index + 1,sum - arr[index], dp);
        if (next_p2 != Integer.MAX_VALUE){
            p2 = next_p2 + x;
        }

        int p3 = Integer.MAX_VALUE;//第三种情况:执行y操作
        int next_p3 = process2(arr,x,y,index + 1,sum - 2 * arr[index], dp);
        if (next_p3 != Integer.MAX_VALUE){
            p3 = y + next_p3;
        }
        dp[index][sum] = Math.min(p1,Math.min(p2,p3));
        return dp[index][sum];
    }
    //贪心(当sum很大的时候,记忆化搜索效果就很差了)
    public static int minOpSteps3(int[] arr,int x,int y){
        int n = arr.length;
        Arrays.sort(arr);
        for (int i = 0,j = n - 1;i <= j;i++,j--){
            int temp = arr[i];
            arr[i] = arr[j];
            arr[j] = temp;
        }
        if (x >= y){
            int sum = 0;
            int ans = 0;
            for (int i = 0;i < n;i++){
                sum += arr[i];
            }
            for (int i = 0;i < n && sum > 0;i++){
                sum -= 2 * arr[i];
                ans += y;
            }
            return ans;
        }else {
            for (int i = n - 2;i >= 0;i--){
                arr[i] += arr[i + 1];
            }
            int benefit = 0;
            int left = mostLeft(arr,0,benefit);// y 为0个时的代价
            int cost = left * x;
            for (int i = 0;i < n - 1;i++){
                benefit += arr[i] - arr[i + 1];
                left = mostLeft(arr,i + 1,benefit);
                cost = Math.min(cost,(left - i - 1) * x + (i + 1) * y);
            }
            return cost;
        }
    }

    private static int mostLeft(int[] arr, int l, int benefit) {
        int r = arr.length - 1;
        int last = arr.length;
        while (l <= r){
            int mid = (l + r) / 2;
            if (arr[mid] <= benefit){
                last = mid;
                r = mid - 1;
            }else {
                l = mid + 1;
            }
        }
        return last;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值