LeetCode刷题——第 71 场双周赛和第 279 场周赛题解

本文介绍了多个编程挑战,涉及数组操作、时间成本计算和位集设计。其中包括根据给定数字划分数组、设置时间的最少代价、删除元素后和的最小差值,以及独立对奇偶下标排序等题目。每个问题都提供了C++和Python的解题代码,旨在测试和提升编程思维和算法能力。
摘要由CSDN通过智能技术生成

第 71 场双周赛

5984. 拆分数位后四位数字的最小和

题目

给你一个四位 正 整数 num 。请你使用 num 中的 数位 ,将 num 拆成两个新的整数 new1 和 new2 。new1 和 new2 中可以有 前导 0 ,且 num 中 所有 数位都必须使用。

比方说,给你 num = 2932 ,你拥有的数位包括:两个 2 ,一个 9 和一个 3 。一些可能的 [new1, new2] 数对为 [22, 93],[23, 92],[223, 9] 和 [2, 329] 。
请你返回可以得到的 new1 和 new2 的 最小 和。

示例 1:

输入:num = 2932 输出:52 解释:可行的 [new1, new2] 数对为 [29, 23] ,[223, 9] 等等。
最小和为数对 [29, 23] 的和:29 + 23 = 52 。

示例 2:

输入:num = 4009 输出:13 解释:可行的 [new1, new2] 数对为 [0, 49] ,[490, 0] 等等。
最小和为数对 [4, 9] 的和:4 + 9 = 13 。

提示:

1000 <= num <= 9999

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/minimum-sum-of-four-digit-number-after-splitting-digits
分析
由题意易得分成的两个数都是两位数时并且十位比个位更小时最小,排序求值即可
C++代码

class Solution {
public:
    int minimumSum(int num) {
        vector<int> a;
        for(int i=0; i < 4; i++){
            a.push_back(num % 10);
            num /= 10;
        }
        sort(a.begin(), a.end());
        return a[0] * 10 + a[2] + a[1] * 10 + a[3];
    }
};

python代码

class Solution(object):
    def minimumSum(self, num):
        """
        :type num: int
        :rtype: int
        """
        ls = []
        while num:
            ls.append(num % 10);
            num /= 10;
        ls = sorted(ls)
        return ls[0] * 10 + ls[1] * 10 + ls[2] + ls[3];

5985. 根据给定数字划分数组

题目
给你一个下标从 0 开始的整数数组 nums 和一个整数 pivot 。请你将 nums 重新排列,使得以下条件均成立:

所有小于 pivot 的元素都出现在所有大于 pivot 的元素 之前 。
所有等于 pivot 的元素都出现在小于和大于 pivot 的元素 中间 。
小于 pivot 的元素之间和大于 pivot 的元素之间的 相对顺序 不发生改变。
更正式的,考虑每一对 pi,pj ,pi 是初始时位置 i 元素的新位置,pj 是初始时位置 j 元素的新位置。对于小于 pivot 的元素,如果 i < j 且 nums[i] < pivot 和 nums[j] < pivot 都成立,那么 pi < pj 也成立。类似的,对于大于 pivot 的元素,如果 i < j 且 nums[i] > pivot 和 nums[j] > pivot 都成立,那么 pi < pj 。
请你返回重新排列 nums 数组后的结果数组。

示例 1:

输入:nums = [9,12,5,10,14,3,10], pivot = 10 输出:[9,5,3,10,10,12,14] 解释:
元素 9 ,5 和 3 小于 pivot ,所以它们在数组的最左边。 元素 12 和 14 大于 pivot ,所以它们在数组的最右边。
小于 pivot 的元素的相对位置和大于 pivot 的元素的相对位置分别为 [9, 5, 3] 和 [12, 14]
,它们在结果数组中的相对顺序需要保留。

示例 2:

输入:nums = [-3,4,3,2], pivot = 2 输出:[-3,2,4,3] 解释: 元素 -3 小于 pivot
,所以在数组的最左边。 元素 4 和 3 大于 pivot ,所以它们在数组的最右边。 小于 pivot 的元素的相对位置和大于 pivot
的元素的相对位置分别为 [-3] 和 [4, 3] ,它们在结果数组中的相对顺序需要保留。

提示:

1 <= nums.length <= 105
-106 <= nums[i] <= 106 pivot 等于 nums 中的一个元素。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/partition-array-according-to-given-pivot

分析
将小于、等于、小于pivot的数分别存储再合并即可
C++代码

class Solution {
public:
    vector<int> pivotArray(vector<int>& nums, int pivot) {
        vector<int> a, b, c;
        for(int i=0; i < nums.size(); i++){
            if(nums[i] < pivot){
                a.push_back(nums[i]);
            }else if(nums[i] == pivot){
                b.push_back(nums[i]);
            }else if(nums[i] > pivot){
                c.push_back(nums[i]);
            }
        }
        for(int i=0; i < b.size(); i++){
            a.push_back(b[i]);
        }
        for(int i=0; i < c.size(); i++){
            a.push_back(c[i]);
        }
        return a;
    }
};

python代码

class Solution(object):
    def pivotArray(self, nums, pivot):
        """
        :type nums: List[int]
        :type pivot: int
        :rtype: List[int]
        """
        a = []
        b = []
        c = []
        for n in nums:
            if n < pivot:
                a.append(n)
            elif n == pivot:
                b.append(n)
            else:
                c.append(n)

        for n in b:
            a.append(n)
        
        for n in c:
            a.append(n)
        
        return a

5986. 设置时间的最少代价

常见的微波炉可以设置加热时间,且加热时间满足以下条件:

至少为 1 秒钟。
至多为 99 分 99 秒。
你可以 最多 输入 4 个数字 来设置加热时间。如果你输入的位数不足 4 位,微波炉会自动加 前缀 0 来补足 4 位。微波炉会将设置好的四位数中,前 两位当作分钟数,后 两位当作秒数。它们所表示的总时间就是加热时间。比方说:

你输入 9 5 4 (三个数字),被自动补足为 0954 ,并表示 9 分 54 秒。
你输入 0 0 0 8 (四个数字),表示 0 分 8 秒。
你输入 8 0 9 0 ,表示 80 分 90 秒。
你输入 8 1 3 0 ,表示 81 分 30 秒。
给你整数 startAt ,moveCost ,pushCost 和 targetSeconds 。一开始,你的手指在数字 startAt 处。将手指移到 任何其他数字 ,需要花费 moveCost 的单位代价。每 输入你手指所在位置的数字一次,需要花费 pushCost 的单位代价。

要设置 targetSeconds 秒的加热时间,可能会有多种设置方法。你想要知道这些方法中,总代价最小为多少。

请你能返回设置 targetSeconds 秒钟加热时间需要花费的最少代价。

请记住,虽然微波炉的秒数最多可以设置到 99 秒,但一分钟等于 60 秒。

示例 1:

输入:startAt = 1, moveCost = 2, pushCost = 1, targetSeconds = 600 输出:6
解释:以下为设置加热时间的所有方法。

  • 1 0 0 0 ,表示 10 分 0 秒。 手指一开始就在数字 1 处,输入 1 (代价为 1),移到 0 处(代价为 2),输入 0(代价为 1),输入 0(代价为 1),输入 0(代价为 1)。 总代价为:1 + 2 + 1 + 1 + 1 = 6
    。这是所有方案中的最小代价。
  • 0 9 6 0,表示 9 分 60 秒。它也表示 600 秒。 手指移到 0 处(代价为 2),输入 0 (代价为 1),移到 9 处(代价为 2),输入 9(代价为 1),移到 6 处(代价为 2),输入 6(代价为 1),移到 0 处(代价为 2),输入 0(代价为
    1)。 总代价为:2 + 1 + 2 + 1 + 2 + 1 + 2 + 1 = 12 。
  • 9 6 0,微波炉自动补全为 0960 ,表示 9 分 60 秒。 手指移到 9 处(代价为 2),输入 9 (代价为 1),移到 6 处(代价为 2),输入 6(代价为 1),移到 0 处(代价为 2),输入 0(代价为 1)。 总代价为:2 + 1 + 2 + 1
  • 2 + 1 = 9 。

示例 2:

输入:startAt = 0, moveCost = 1, pushCost = 2, targetSeconds = 76 输出:6
解释:最优方案为输入两个数字 7 6,表示 76 秒。 手指移到 7 处(代价为 1),输入 7 (代价为 2),移到 6 处(代价为
1),输入 6(代价为 2)。总代价为:1 + 2 + 1 + 2 = 6 其他可行方案为 0076 ,076 ,0116 和 116
,但是它们的代价都比 6 大。

提示:

0 <= startAt <= 9 1 <= moveCost, pushCost <= 105
1 <= targetSeconds <=6039

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/minimum-cost-to-set-cooking-time
分析
这道题可以用深搜做,但是个人更偏向于这是一道阅读理解题,首先将target转换成时间,时间上有尽可能的满足分钟最大或秒最大两种情况。尤其要注意startAt不是指针位置,而是指向的数值的位置
代码

class Solution {
public:
    int minCostSetTime(int startAt, int moveCost, int pushCost, int targetSeconds) {
        vector<pair<int, int>> v;
        int m = targetSeconds / 60, s = targetSeconds % 60;
        if(m >= 0 && m <= 99 && s >= 0 && s <= 99){
            v.push_back(make_pair(m, s));
        }
        if(m-1 >= 0 && m-1 <= 99 && s+60 >= 0 && s+60 <= 99){
            v.push_back(make_pair(m-1, s+60));
        }
        int ans = ((unsigned)(-1)>>1);
        int start;
        for(int i=0; i < v.size(); i++){
            int idx=0, tmp = 0;
            auto & [a, b] = v[i];
            string s=to_string(a*100 + b);
            //cout<<s<<endl;
            start = startAt;
            for (int j = 0; j < s.size(); j++) {
                tmp += pushCost;
                if (start != s[j] - '0') {
                    tmp += moveCost;
                }
                if(i==1){
                    cout<<start<<" "<<s[j]<<endl;
                }
                start = s[j] - '0';
            }
            ans = min(ans, tmp);
        }
        return ans;
    }
};

5987. 删除元素后和的最小差值

给你一个下标从 0 开始的整数数组 nums ,它包含 3 * n 个元素。

你可以从 nums 中删除 恰好 n 个元素,剩下的 2 * n 个元素将会被分成两个 相同大小 的部分。

前面 n 个元素属于第一部分,它们的和记为 sumfirst 。
后面 n 个元素属于第二部分,它们的和记为 sumsecond 。
两部分和的 差值 记为 sumfirst - sumsecond 。

比方说,sumfirst = 3 且 sumsecond = 2 ,它们的差值为 1 。
再比方,sumfirst = 2 且 sumsecond = 3 ,它们的差值为 -1 。
请你返回删除 n 个元素之后,剩下两部分和的 差值的最小值 是多少。

示例 1:

输入:nums = [3,1,2] 输出:-1 解释:nums 有 3 个元素,所以 n = 1 。 所以我们需要从 nums 中删除 1
个元素,并将剩下的元素分成两部分。

  • 如果我们删除 nums[0] = 3 ,数组变为 [1,2] 。两部分和的差值为 1 - 2 = -1 。
  • 如果我们删除 nums[1] = 1 ,数组变为 [3,2] 。两部分和的差值为 3 - 2 = 1 。
  • 如果我们删除 nums[2] = 2 ,数组变为 [3,1] 。两部分和的差值为 3 - 1 = 2 。 两部分和的最小差值为 min(-1,1,2) = -1 。

示例 2:

输入:nums = [7,9,5,8,1,3] 输出:1 解释:n = 2 。所以我们需要删除 2 个元素,并将剩下元素分为 2 部分。
如果我们删除元素 nums[2] = 5 和 nums[3] = 8 ,剩下元素为 [7,9,1,3] 。和的差值为 (7+9) -
(1+3) = 12 。 为了得到最小差值,我们应该删除 nums[1] = 9 和 nums[4] = 1 ,剩下的元素为
[7,5,8,3] 。和的差值为 (7+5) - (8+3) = 1 。 观察可知,最优答案为 1 。

提示:

nums.length == 3 * n
1 <= n <= 105
1 <= nums[i] <= 105

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/minimum-difference-in-sums-after-removal-of-elements
代码

class Solution {
public:
    long long minimumDifference(vector<int>& nums) {
        int n = nums.size(), k = n/3;
        
        // s1[i]: 数组从 0 ~ i 的最小的 n / 3 个元素的和;
        // s2[i]: 数组从 i+1 ~ n-1 的最大的 n/3 个元素的和;
        vector<long long> s1(n, 0), s2(n, 0);
        
        // 左侧最小的 n / 3 个元素,用大顶堆
        priority_queue<int> small;
        
        // 从左到右动态维护左侧最小的 n/3 个元素的和
        for(int i = 0; i < 2*k; ++i) {
            s1[i] = (i > 0)? s1[i-1] : 0;
            small.push(nums[i]);
            s1[i] += nums[i];
            if(small.size() > k) {
                s1[i] -= small.top(), small.pop();
            }
        }
        
        // 右侧最大的 n / 3 个元素,用小顶堆
        priority_queue<int, vector<int>, greater<int>> big;
        
        // 从右到左动态维护右侧最大的 n/3 个元素的和
        for(int i = n-2; i >= k-1; --i) {
            s2[i] = s2[i+1];
            big.push(nums[i+1]);
            s2[i] += nums[i+1]; 
            if(big.size() > k) {
                s2[i] -= big.top(), big.pop();
            }
        }
        
        // 统计答案
        long long res = 1e15;
        for(int i = k-1; i < 2*k; ++i) {
            res = min(res, s1[i] - s2[i]);
        }
        
        return res;
    }
};

第 279 场周赛

6000. 对奇偶下标分别排序

给你一个下标从 0 开始的整数数组 nums 。根据下述规则重排 nums 中的值:

按 非递增 顺序排列 nums 奇数下标 上的所有值。
举个例子,如果排序前 nums = [4,1,2,3] ,对奇数下标的值排序后变为 [4,3,2,1] 。奇数下标 1 和 3 的值按照非递增顺序重排。
按 非递减 顺序排列 nums 偶数下标 上的所有值。
举个例子,如果排序前 nums = [4,1,2,3] ,对偶数下标的值排序后变为 [2,1,4,3] 。偶数下标 0 和 2 的值按照非递减顺序重排。
返回重排 nums 的值之后形成的数组。

示例 1:

输入:nums = [4,1,2,3] 输出:[2,3,4,1] 解释: 首先,按非递增顺序重排奇数下标(1 和 3)的值。 所以,nums
从 [4,1,2,3] 变为 [4,3,2,1] 。 然后,按非递减顺序重排偶数下标(0 和 2)的值。 所以,nums 从
[4,1,2,3] 变为 [2,3,4,1] 。 因此,重排之后形成的数组是 [2,3,4,1] 。

示例 2:

输入:nums = [2,1] 输出:[2,1] 解释: 由于只有一个奇数下标和一个偶数下标,所以不会发生重排。 形成的结果数组是
[2,1] ,和初始数组一样。

提示:

1 <= nums.length <= 100 1 <= nums[i] <= 100

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/sort-even-and-odd-indices-independently
分析
分部分排序即可
C++代码

class Solution {
public:
    vector<int> sortEvenOdd(vector<int>& nums) {
        for(int i=0; i < nums.size(); i+=2){
            for(int j=i+2; j < nums.size(); j+= 2){
                if(nums[i] > nums[j]){
                    int tmp = nums[i];
                    nums[i] = nums[j];
                    nums[j] = tmp;
                }
            }
        }
        for(int i=1; i < nums.size(); i+=2){
            for(int j=i+2; j < nums.size(); j+= 2){
                if(nums[i] < nums[j]){
                    int tmp = nums[i];
                    nums[i] = nums[j];
                    nums[j] = tmp;
                }
            }
        }
        return nums;
    }
};

python代码

class Solution:
    def sortEvenOdd(self, nums: List[int]) -> List[int]:
        nums[::2] = sorted(nums[::2])
        nums[1::2] = sorted(nums[1::2], reverse=True)
        return nums

6001. 重排数字的最小值

给你一个整数 num 。重排 num 中的各位数字,使其值 最小化 且不含 任何 前导零。

返回不含前导零且值最小的重排数字。

注意,重排各位数字后,num 的符号不会改变。

示例 1:

输入:num = 310 输出:103 解释:310 中各位数字的可行排列有:013、031、103、130、301、310 。
不含任何前导零且值最小的重排数字是 103 。

示例 2:

输入:num = -7605 输出:-7650 解释:-7605
中各位数字的部分可行排列为:-7650、-6705、-5076、-0567。 不含任何前导零且值最小的重排数字是 -7650 。

提示:

-1015 <= num <= 1015

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/smallest-value-of-the-rearranged-number
C++代码

class Solution {
public:
    long long smallestNumber(long long num) {
        bool flag=true;
        if(num < 0){
            flag = false;
            num = -num;
        }
        vector<int> v;
        while(num){
            v.push_back(num % 10);
            num /= 10;
        }
        sort(v.begin(), v.end());
        long long ans = 0;
        if(flag){
            if(v.size() == 0){
                return 0;
            }
            if(v[0] == 0){
                int cnt=0;
                int cur=0;
                while(v[cur] == 0){
                    cnt++;
                    cur++;
                }
                ans = v[cur];
                while(cnt--){
                    ans *= 10;
                }
                for(int i=cur+1; i < v.size(); i++){
                    ans *= 10;
                    ans += v[i];
                }
            }else{
                for(int i=0; i < v.size(); i++){
                    ans *= 10;
                    ans += v[i];
                }
            }
            return ans;
        }else{
            for(int i=v.size()-1; i >= 0 ; i--){
                ans *= 10;
                ans += v[i];
            }
            return -ans;
        }
    }
};

python代码

class Solution:
    def smallestNumber(self, num: int) -> int:
        flag = num > 0
        if flag == False:
            num = -num

        ls = []
        while num:
            ls.append(num % 10)
            num //= 10
        
        ls = sorted(ls);
        ans=0
        
        if flag:
            cur = 0
            while ls[cur] == 0:
                cur+=1

            ans = ls[cur]
         
            for i in range(cur):
                ans *= 10
            for i in range(cur+1, len(ls)):
                ans *= 10
                ans += ls[i]
            
            return ans
        else:
            for i in range(len(ls)-1, -1, -1):
                ans *= 10
                ans += ls[i]
            
            return -ans

6002. 设计位集

位集 Bitset 是一种能以紧凑形式存储位的数据结构。

请你实现 Bitset 类。

Bitset(int size) 用 size 个位初始化 Bitset ,所有位都是 0 。
void fix(int idx) 将下标为 idx 的位上的值更新为 1 。如果值已经是 1 ,则不会发生任何改变。
void unfix(int idx) 将下标为 idx 的位上的值更新为 0 。如果值已经是 0 ,则不会发生任何改变。
void flip() 翻转 Bitset 中每一位上的值。换句话说,所有值为 0 的位将会变成 1 ,反之亦然。
boolean all() 检查 Bitset 中 每一位 的值是否都是 1 。如果满足此条件,返回 true ;否则,返回 false 。
boolean one() 检查 Bitset 中 是否 至少一位 的值是 1 。如果满足此条件,返回 true ;否则,返回 false 。
int count() 返回 Bitset 中值为 1 的位的 总数 。
String toString() 返回 Bitset 的当前组成情况。注意,在结果字符串中,第 i 个下标处的字符应该与 Bitset 中的第 i 位一致。

示例:

输入 [“Bitset”, “fix”, “fix”, “flip”, “all”, “unfix”, “flip”, “one”,
“unfix”, “count”, “toString”] [[5], [3], [1], [], [], [0], [], [],
[0], [], []] 输出 [null, null, null, null, false, null, null, true,
null, 2, “01010”]

解释 Bitset bs = new Bitset(5); // bitset = “00000”. bs.fix(3); // 将
idx = 3 处的值更新为 1 ,此时 bitset = “00010” 。 bs.fix(1); // 将 idx = 1
处的值更新为 1 ,此时 bitset = “01010” 。 bs.flip(); // 翻转每一位上的值,此时 bitset =
“10101” 。 bs.all(); // 返回 False ,bitset 中的值不全为 1 。 bs.unfix(0);
// 将 idx = 0 处的值更新为 0 ,此时 bitset = “00101” 。 bs.flip(); //
翻转每一位上的值,此时 bitset = “11010” 。 bs.one(); // 返回 True ,至少存在一位的值为 1
。 bs.unfix(0); // 将 idx = 0 处的值更新为 0 ,此时 bitset = “01010” 。
bs.count(); // 返回 2 ,当前有 2 位的值为 1 。 bs.toString(); // 返回 “01010” ,即
bitset 的当前组成情况。

提示:

1 <= size <= 105 0 <= idx <= size - 1 至多调用
fix、unfix、flip、all、one、count 和 toString 方法 总共 105 次 至少调用 all、one、count
或 toString 方法一次 至多调用 toString 方法 5 次

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/design-bitset
分析
从题意看出应该是二进制的题目,但是因为size过大,所以C++中用字符串表示二进制数,同时因为反转步骤和统计步骤容易超时,我们同步存储反转的结果和1的个数。
C++代码

class Bitset {
public:
    string n;
    string ren;
    int ones=0;
    int csize;
    Bitset(int size) {
        csize = size;
        for(int i=0; i < size; i++){
            n += "0";
            ren += "1";
        }
    }
    void fix(int idx) {
        if(n[idx] == '0'){
            n[idx] = '1';
            ren[idx] = '0';
            ones++;
        }
    }
    
    void unfix(int idx) {
        if(n[idx] == '1'){
            n[idx] = '0';
            ren[idx] = '1';
            ones--;
        }
    }
    
    void flip() {
        string tmp = n;
        n = ren;
        ren = tmp;
        ones = csize - ones;
    }
    
    bool all() {
        return ones == csize;
    }
    
    bool one() {
        return ones > 0;
    }
    
    int count() {
        return ones;
    }
    
    string toString() {
        return n;
    }
};

/**
 * Your Bitset object will be instantiated and called as such:
 * Bitset* obj = new Bitset(size);
 * obj->fix(idx);
 * obj->unfix(idx);
 * obj->flip();
 * bool param_4 = obj->all();
 * bool param_5 = obj->one();
 * int param_6 = obj->count();
 * string param_7 = obj->toString();
 */

python代码

class Bitset:

    def __init__(self, size: int):
        self.num = 0
        self.len = size
        self.total = 0
        self.power = 1 << self.len

    def fix(self, idx: int) -> None:
        idx = self.len - idx - 1
        if not (self.num >> idx) & 1:
            self.total += 1
        self.num |= (1 << idx)

    def unfix(self, idx: int) -> None:
        idx = self.len - idx - 1
        if (self.num >> idx) & 1:
            self.total -= 1
            self.num ^= (1 << idx)

    def flip(self) -> None:
        self.total = self.len - self.total
        self.num = self.power - 1 - self.num

    def all(self) -> bool:
        return self.total == self.len

    def one(self) -> bool:
        return self.total > 0

    def count(self) -> int:
        return self.total

    def toString(self) -> str:
        s = bin(self.num)[2:]
        return "0" * (self.len - len(s)) + s


# Your Bitset object will be instantiated and called as such:
# obj = Bitset(size)
# obj.fix(idx)
# obj.unfix(idx)
# obj.flip()
# param_4 = obj.all()
# param_5 = obj.one()
# param_6 = obj.count()
# param_7 = obj.toString()

6003. 移除所有载有违禁货物车厢所需的最少时间

给你一个下标从 0 开始的二进制字符串 s ,表示一个列车车厢序列。s[i] = ‘0’ 表示第 i 节车厢 不 含违禁货物,而 s[i] = ‘1’ 表示第 i 节车厢含违禁货物。

作为列车长,你需要清理掉所有载有违禁货物的车厢。你可以不限次数执行下述三种操作中的任意一个:

从列车 左 端移除一节车厢(即移除 s[0]),用去 1 单位时间。
从列车 右 端移除一节车厢(即移除 s[s.length - 1]),用去 1 单位时间。
从列车车厢序列的 任意位置 移除一节车厢,用去 2 单位时间。
返回移除所有载有违禁货物车厢所需要的 最少 单位时间数。

注意,空的列车车厢序列视为没有车厢含违禁货物。

示例 1:

输入:s = “1100101” 输出:5 解释: 一种从序列中移除所有载有违禁货物的车厢的方法是:

  • 从左端移除一节车厢 2 次。所用时间是 2 * 1 = 2 。
  • 从右端移除一节车厢 1 次。所用时间是 1 。
  • 移除序列中间位置载有违禁货物的车厢。所用时间是 2 。 总时间是 2 + 1 + 2 = 5 。

一种替代方法是:

  • 从左端移除一节车厢 2 次。所用时间是 2 * 1 = 2 。
  • 从右端移除一节车厢 3 次。所用时间是 3 * 1 = 3 。 总时间也是 2 + 3 = 5 。

5 是移除所有载有违禁货物的车厢所需要的最少单位时间数。 没有其他方法能够用更少的时间移除这些车厢。

示例 2:

输入:s = “0010” 输出:2 解释: 一种从序列中移除所有载有违禁货物的车厢的方法是:

  • 从左端移除一节车厢 3 次。所用时间是 3 * 1 = 3 。 总时间是 3.

另一种从序列中移除所有载有违禁货物的车厢的方法是:

  • 移除序列中间位置载有违禁货物的车厢。所用时间是 2 。 总时间是 2.

另一种从序列中移除所有载有违禁货物的车厢的方法是:

  • 从右端移除一节车厢 2 次。所用时间是 2 * 1 = 2 。 总时间是 2.

2 是移除所有载有违禁货物的车厢所需要的最少单位时间数。 没有其他方法能够用更少的时间移除这些车厢。

提示:

1 <= s.length <= 2 * 105
s[i] 为 ‘0’ 或 ‘1’

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/minimum-time-to-remove-all-cars-containing-illegal-goods
分析
动态规划的题目,不妨假设i为当前位置dp[i]为从右删(包括到中间删除)到i的最小值,然后遍历查询从左侧删到i即可
C++代码

class Solution {
public:
    int minimumTime(string s) {
        int n = s.size();
        int dp[n+1];
        memset(dp, 0, sizeof(dp));
        for(int i=n-1; i >= 0; i--){
            if(s[i] == '0'){
                dp[i] = dp[i+1];
            }else{
                dp[i] = min(dp[i+1]+2, n - i);
            }
        }
        int cur = 0;
        int ans = dp[0];
        for(int i=0; i < n; i++){
            if(s[i] == '1'){
                cur = min(cur+2, i+1);
                ans = min(ans, cur + dp[i+1]);
            }
        }
        return ans;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

艾醒(AiXing-w)

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

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

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

打赏作者

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

抵扣说明:

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

余额充值