LeetCode Weekly Contest 183

5376. 非递增顺序的最小子序列

给你一个数组 nums,请你从中抽取一个子序列,满足该子序列的元素之和 严格 大于未包含在该子序列中的各元素之和。

如果存在多个解决方案,只需返回 长度最小 的子序列。如果仍然有多个解决方案,则返回 元素之和最大 的子序列。

与子数组不同的地方在于,「数组的子序列」不强调元素在原数组中的连续性,也就是说,它可以通过从数组中分离一些(也可能不分离)元素得到。

注意,题目数据保证满足所有约束条件的解决方案是 唯一 的。同时,返回的答案应当按 非递增顺序 排列。

示例 1:

输入:nums = [4,3,10,9,8]
输出:[10,9]
解释:子序列 [10,9] 和 [10,8] 是最小的、满足元素之和大于其他各元素之和的子序列。但是 [10,9] 的元素之和最大。
示例 2:

输入:nums = [4,4,7,6,7]
输出:[7,7,6]
解释:子序列 [7,7] 的和为 14 ,不严格大于剩下的其他元素之和(14 = 4 + 4 + 6)。因此,[7,6,7] 是满足题意的最小子序列。注意,元素按非递增顺序返回。
示例 3:

输入:nums = [6]
输出:[6]

提示:

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

思路

从大到小排序,贪心地取最大的若干个数直到符合条件

代码

class Solution {
    public List<Integer> minSubsequence(int[] nums) {
        Arrays.sort(nums);
        int sum = 0, ans = 0, i = 0, n = nums.length;
        ArrayList<Integer> ret = new ArrayList<>();
        for (int num: nums) {
            sum += num;
        }
        for (i=n-1; i>=0; --i) {
            ans += nums[i];
            ret.add(nums[i]);
            if (2 * ans > sum) {
                break;
            }
        }
        return ret;
    }
}

5377. 将二进制表示减到 1 的步骤数

给你一个以二进制形式表示的数字 s 。请你返回按下述规则将其减少到 1 所需要的步骤数:

如果当前数字为偶数,则将其除以 2 。

如果当前数字为奇数,则将其加上 1 。

题目保证你总是可以按上述规则将测试用例变为 1 。

示例 1:

输入:s = “1101”
输出:6
解释:“1101” 表示十进制数 13 。
Step 1) 13 是奇数,加 1 得到 14
Step 2) 14 是偶数,除 2 得到 7
Step 3) 7 是奇数,加 1 得到 8
Step 4) 8 是偶数,除 2 得到 4
Step 5) 4 是偶数,除 2 得到 2
Step 6) 2 是偶数,除 2 得到 1
示例 2:

输入:s = “10”
输出:1
解释:“10” 表示十进制数 2 。
Step 1) 2 是偶数,除 2 得到 1
示例 3:

输入:s = “1”
输出:0

提示:

1 <= s.length <= 500
s 由字符 ‘0’ 或 ‘1’ 组成。
s[0] == ‘1’

思路

递归。这题因为Java的字符串操作比较繁琐,所以用了Python3提交

代码

class Solution:
    def add1(self, s: str) -> str:
        lst = list(s)
        addi = True
        for i in reversed(range(len(s))):
            if addi and lst[i] == '1':
                lst[i] = '0'
                addi = True
            elif addi and lst[i] == '0':
                lst[i] = '1'
                addi = False
            if not addi:
                break
        s = ''.join(lst)
        if addi:
            s = '1' + s
        return s
                  
    def numSteps(self, s: str) -> int:
        if s == '1':
            return 0
        if s[-1] == '1':
            return 1 + self.numSteps(self.add1(s))
        n = len(s)
        for i in reversed(range(n)):
            if s[i] != '0':
                break
        return n - 1 - i + self.numSteps(s[:i+1])

5195. 最长快乐字符串

如果字符串中不含有任何 ‘aaa’,‘bbb’ 或 ‘ccc’ 这样的字符串作为子串,那么该字符串就是一个「快乐字符串」。

给你三个整数 a,b ,c,请你返回 任意一个 满足下列全部条件的字符串 s:

s 是一个尽可能长的快乐字符串。
s 中 最多 有a 个字母 ‘a’、b 个字母 ‘b’、c 个字母 ‘c’ 。
s 中只含有 ‘a’、‘b’ 、‘c’ 三种字母。
如果不存在这样的字符串 s ,请返回一个空字符串 “”。

示例 1:

输入:a = 1, b = 1, c = 7
输出:“ccaccbcc”
解释:“ccbccacc” 也是一种正确答案。
示例 2:

输入:a = 2, b = 2, c = 1
输出:“aabbc”
示例 3:

输入:a = 7, b = 1, c = 0
输出:“aabaa”
解释:这是该测试用例的唯一正确答案。

提示:

0 <= a, b, c <= 100
a + b + c > 0

思路

贪心。分情况讨论,每次取出现次数最多的。我比赛的时候想得太复杂了,写得太繁琐了。

代码

class Solution {
    private class ABCcnt implements Comparable<ABCcnt> {
        public int cnt;
        public char ch;
        
        public ABCcnt(int _cnt, char _ch) {
            cnt = _cnt;
            ch = _ch;
        }
        
        @Override
        public int compareTo(ABCcnt other) {
            return other.cnt - cnt;
        }
    }
    
    public String longestDiverseString(int a, int b, int c) {
        if (a == 0 && b == 0 && c == 0) {
            return "";
        }
        ABCcnt[] cnts = new ABCcnt[3];
        StringBuilder sb = new StringBuilder();
        int i = 0;
        cnts[0] = new ABCcnt(a, 'a');
        cnts[1] = new ABCcnt(b, 'b');
        cnts[2] = new ABCcnt(c, 'c');
        Arrays.sort(cnts);
        if (cnts[1].cnt == 0) {
            cnts[0].cnt = Math.min(2, cnts[0].cnt);
            for (i=0; i<cnts[0].cnt; ++i) {
                sb.append(cnts[0].ch);
            }
            return sb.toString();
        }
        if (cnts[0].cnt >= 2 * (cnts[1].cnt + cnts[2].cnt + 1)) {
            sb.append(cnts[0].ch);
            sb.append(cnts[0].ch);
            for (i=0; i<cnts[1].cnt; ++i) {
                sb.append(cnts[1].ch);
                sb.append(cnts[0].ch);
                sb.append(cnts[0].ch);
            }
            for (i=0; i<cnts[2].cnt; ++i) {
                sb.append(cnts[2].ch);
                sb.append(cnts[0].ch);
                sb.append(cnts[0].ch);
            }
            return sb.toString();
        } else if (cnts[0].cnt >= 2 * (cnts[1].cnt + 1)) {
            if (cnts[2].cnt == 0) {
                sb.append(cnts[0].ch);
                sb.append(cnts[0].ch);
                for (i=0; i<cnts[1].cnt; ++i) {
                    sb.append(cnts[1].ch);
                    sb.append(cnts[0].ch);
                    sb.append(cnts[0].ch);
                }
                return sb.toString();
            } else {
                cnts[0].cnt -= 2;
                cnts[1].cnt -= 1;
                sb.append(cnts[0].ch);
                sb.append(cnts[0].ch);
                sb.append(cnts[1].ch);
                for (i=0; i<3; ++i) {
                    if (cnts[i].ch == 'a') {
                        a = cnts[i].cnt;
                    } else if (cnts[i].ch == 'b') {
                        b = cnts[i].cnt;
                    } else if (cnts[i].ch == 'c') {
                        c = cnts[i].cnt;
                    }
                }
                return sb.toString() + longestDiverseString(a, b, c);
            }
        }
        if (cnts[0].cnt == cnts[1].cnt && cnts[1].cnt == cnts[2].cnt) {
            for (i=0; i<cnts[0].cnt; ++i) {
                sb.append(cnts[0].ch);
                sb.append(cnts[1].ch);
                sb.append(cnts[2].ch);
            }
            return sb.toString();
        }
        if (cnts[0].cnt == cnts[1].cnt) {
            cnts[0].cnt -= 1;
            cnts[1].cnt -= 1;
            sb.append(cnts[0].ch);
            sb.append(cnts[1].ch);
            for (i=0; i<3; ++i) {
                if (cnts[i].ch == 'a') {
                    a = cnts[i].cnt;
                } else if (cnts[i].ch == 'b') {
                    b = cnts[i].cnt;
                } else if (cnts[i].ch == 'c') {
                    c = cnts[i].cnt;
                }
            }
            return sb.toString() + longestDiverseString(a, b, c);
        }
        int num0 = Math.min(2, cnts[0].cnt), num1 = Math.min(1, cnts[1].cnt);
        for (i=0; i<num0; ++i) {
            sb.append(cnts[0].ch);
        }
        for (i=0; i<num1; ++i) {
            sb.append(cnts[1].ch);
        }        
        cnts[0].cnt -= num0;
        cnts[1].cnt -= num1;
        for (i=0; i<3; ++i) {
            if (cnts[i].ch == 'a') {
                a = cnts[i].cnt;
            } else if (cnts[i].ch == 'b') {
                b = cnts[i].cnt;
            } else if (cnts[i].ch == 'c') {
                c = cnts[i].cnt;
            }
        }
        return sb.toString() + longestDiverseString(a, b, c);
    }
}

5379. 石子游戏 III

Alice 和 Bob 用几堆石子在做游戏。几堆石子排成一行,每堆石子都对应一个得分,由数组 stoneValue 给出。

Alice 和 Bob 轮流取石子,Alice 总是先开始。在每个玩家的回合中,该玩家可以拿走剩下石子中的的前 1、2 或 3 堆石子 。比赛一直持续到所有石头都被拿走。

每个玩家的最终得分为他所拿到的每堆石子的对应得分之和。每个玩家的初始分数都是 0 。比赛的目标是决出最高分,得分最高的选手将会赢得比赛,比赛也可能会出现平局。

假设 Alice 和 Bob 都采取 最优策略 。如果 Alice 赢了就返回 “Alice” ,Bob 赢了就返回 “Bob”,平局(分数相同)返回 “Tie” 。

示例 1:

输入:values = [1,2,3,7]
输出:“Bob”
解释:Alice 总是会输,她的最佳选择是拿走前三堆,得分变成 6 。但是 Bob 的得分为 7,Bob 获胜。
示例 2:

输入:values = [1,2,3,-9]
输出:“Alice”
解释:Alice 要想获胜就必须在第一个回合拿走前三堆石子,给 Bob 留下负分。
如果 Alice 只拿走第一堆,那么她的得分为 1,接下来 Bob 拿走第二、三堆,得分为 5 。之后 Alice 只能拿到分数 -9 的石子堆,输掉比赛。
如果 Alice 拿走前两堆,那么她的得分为 3,接下来 Bob 拿走第三堆,得分为 3 。之后 Alice 只能拿到分数 -9 的石子堆,同样会输掉比赛。
注意,他们都应该采取 最优策略 ,所以在这里 Alice 将选择能够使她获胜的方案。
示例 3:

输入:values = [1,2,3,6]
输出:“Tie”
解释:Alice 无法赢得比赛。如果她决定选择前三堆,她可以以平局结束比赛,否则她就会输。
示例 4:

输入:values = [1,2,3,-1,-2,-3,7]
输出:“Alice”
示例 5:

输入:values = [-1,-2,-3]
输出:“Tie”

提示:

1 <= values.length <= 50000
-1000 <= values[i] <= 1000

思路

博弈论,用动态规划的方法求解。dp[i]表示从第i个石子开始往后取,先手的人最多可以取到的最大分数。
边界条件:

dp[n] = 0

递推公式(从下标n向下标0递推):

s = sum(stoneValue[i:])
dp[i] = max(	s - dp[i+1], 	# 先手取1个石子,后手从第i+1个石子开始取
				s - dp[i+2],	# 先手取2个石子,后手从第i+2个石子开始取
				s - dp[i+3])	# 先手取3个石子,后手从第i+3个石子开始取

Alice的最大分数:dp[0], Bob的最大分数:sumAll - dp[0]

代码

class Solution {
    public String stoneGameIII(int[] stoneValue) {
        int n = stoneValue.length, i = 0, sum = 0, j = 0;
        int[] dp = new int[n+1];
        for (i=n-1; i>=0; --i) {
            dp[i] = Integer.MIN_VALUE;
            sum += stoneValue[i];
            for (j=i+1; j<=n && j<=i+3; ++j) {
                dp[i] = Math.max(dp[i], sum - dp[j]);
            }
        }
        if (2 * dp[0] == sum) {
            return "Tie";
        } else if (2 * dp[0] > sum) {
            return "Alice";
        } else {
            return "Bob";
        }
    }
}

你可能感兴趣的:(LeetCode)