• Leetcode 1769. 移动所有球到每个盒子所需的最小操作数


    有 n 个盒子。给你一个长度为 n 的二进制字符串 boxes ,其中 boxes[i] 的值为 '0' 表示第 i 个盒子是 空 的,而 boxes[i] 的值为 '1' 表示盒子里有 一个 小球。
    
    在一步操作中,你可以将 一个 小球从某个盒子移动到一个与之相邻的盒子中。第 i 个盒子和第 j 个盒子相邻需满足 abs(i - j) == 1 。注意,操作执行后,某些盒子中可能会存在不止一个小球。
    
    返回一个长度为 n 的数组 answer ,其中 answer[i] 是将所有小球移动到第 i 个盒子所需的 最小 操作数。
    
    每个 answer[i] 都需要根据盒子的 初始状态 进行计算。
    
     
    
    示例 1:
    
    输入:boxes = "110"
    输出:[1,1,3]
    解释:每个盒子对应的最小操作数如下:
    1) 第 1 个盒子:将一个小球从第 2 个盒子移动到第 1 个盒子,需要 1 步操作。
    2) 第 2 个盒子:将一个小球从第 1 个盒子移动到第 2 个盒子,需要 1 步操作。
    3) 第 3 个盒子:将一个小球从第 1 个盒子移动到第 3 个盒子,需要 2 步操作。将一个小球从第 2 个盒子移动到第 3 个盒子,需要 1 步操作。共计 3 步操作。
    
    示例 2:
    
    输入:boxes = "001011"
    输出:[11,8,5,4,3,4]
    
     
    
    提示:
    
        n == boxes.length
        1 <= n <= 2000
        boxes[i] 为 '0' 或 '1'
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    解法一:前缀和

    对于每个位置将其他小球放置到该位置 i i i等于左边和右边所有的 1 1 1移动到该位置 i i i的总步数之和。定义 l e f t [ i ] left[i] left[i]代表左边所有的 1 1 1移动到位置i需要的步数,定义 c n t cnt cnt [ 1 , i − 1 ] [1,i - 1] [1,i1]中1的个数,那么对于当前 i i i位置 l e f t [ i ] = c n t + l e f t [ i − 1 ] left[i] = cnt + left[i - 1] left[i]=cnt+left[i1]。更新完 l e f t [ i ] left[i] left[i]后更新cnt继续遍历。同理可以定义 r i g h t [ i ] right[i] right[i]代表 i i i右边所有的1移动到该位置花费的步数。
    在这里插入图片描述

    • 时间复杂度: O ( n ) O(n) O(n)
    • 空间复杂度: O ( n ) O(n) O(n)
    class Solution {
        public int[] minOperations(String boxes) {
            int n = boxes.length();
            char[] arr = (" " + boxes).toCharArray();
            int[] left = new int[n + 5], right = new int[n + 5], ans = new int[n];
            int cnt1 = 0, cnt2 = 0;
            for (int i = 1; i <= n; i++) {
                left[i] = cnt1 + left[i - 1];
                cnt1 += (arr[i] - '0'); 
                right[n - i + 1] = cnt2 + right[n - i + 2];
                cnt2 += (arr[n - i + 1] - '0');
            } 
            for (int i = 1; i <= n; i++) ans[i - 1] = left[i] + right[i];
            return ans;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    class Solution {
    public:
        vector<int> minOperations(string boxes) {
            int n = boxes.length(); 
            vector<int> left(n + 5, 0), right(n + 5, 0), ans(n, 0);
            int cnt1 = 0, cnt2 = 0;
            for (int i = 1; i <= n; i++) {
                left[i] = cnt1 + left[i - 1];
                cnt1 += (boxes[i - 1] - '0'); 
                right[n - i + 1] = cnt2 + right[n - i + 2];
                cnt2 += (boxes[n - i] - '0');
            } 
            for (int i = 1; i <= n; i++) ans[i - 1] = left[i] + right[i];
            return ans;    
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    解法二:前缀和优化

    在计算答案的时候再计算left前缀和的值。首先计算出解法一中right[1]的结果保存在right中,在计算答案的时候更新left和right即可。

    • 时间复杂度: O ( n ) O(n) O(n)
    • 空间复杂度: O ( 1 ) O(1) O(1)
    class Solution {
        public int[] minOperations(String boxes) {
            int n = boxes.length();
            char[] arr = (" " + boxes).toCharArray();
            int left = 0, right = 0, cnt1 = 0, cnt2 = 0; 
            int[] ans = new int[n];
            for (int i = n; i >= 1; i--) { 
                right += cnt2;
                cnt2 += arr[i] - '0';
            } 
            for (int i = 1; i <= n; i++, left += cnt1, right -= cnt2) {
                ans[i - 1] = left + right; 
                cnt1 += arr[i] - '0'; 
                cnt2 -= arr[i] - '0'; 
            }
            return ans;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    class Solution {
    public:
        vector<int> minOperations(string boxes) {
            int n = boxes.length(); 
            int left = 0, right = 0, cnt1 = 0, cnt2 = 0; 
            vector<int> ans(n);
            for (int i = n; i >= 1; i--) { 
                right += cnt2;
                cnt2 += boxes[i - 1] - '0';
            } 
            for (int i = 1; i <= n; i++, left += cnt1, right -= cnt2) {
                ans[i - 1] = left + right; 
                cnt1 += boxes[i - 1] - '0'; 
                cnt2 -= boxes[i - 1] - '0'; 
            }
            return ans; 
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 或者两次遍历进行答案更新。
    class Solution {
        public int[] minOperations(String boxes) {
            int n = boxes.length();
            char[] arr = (" " + boxes).toCharArray();
            int left = 0, cnt1 = 0, cnt2 = 0; 
            int[] ans = new int[n];
            for (int i = n; i >= 1; i--) { 
                ans[i - 1] += (i < n ? ans[i] : 0) +  cnt2; 
                cnt2 += arr[i] - '0';
            } 
            for (int i = 1; i <= n; i++, left += cnt1) {
                ans[i - 1] += left; 
                cnt1 += arr[i] - '0';  
            }
            return ans;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
  • 相关阅读:
    使用gulp助力前端自动化
    SQL分页查询
    如何将系统盘MBR转GPT?无损教程分享!
    程序读取输入数据
    吴恩达机器学习笔记(一)
    win10系统单独编译和使用WebRTC的回声消除(AEC)、音频增益(AGC)、去噪(NS)模块
    如何快速同步第三方平台数据?
    读An All-in-One Network for Dehazing and Beyond
    【汇编语言】push pop/关于段
    如何选择合适的工业相机
  • 原文地址:https://blog.csdn.net/qq_41280600/article/details/128140419