Java实现 183 LeetCode周赛

第一题 【简单】
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]

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/minimum-subsequence-in-non-increasing-order
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

package _183leetcode周赛;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class _01非递增顺序的最小子序列 {
//就是从数组中随机选出一些数之和要大于剩下没选的和
	//然后还要选出长度最短的,如果长度最短的有多个就选出元素和最大的
	//解:
	//将数组大到小排序,当之和大于剩下的数之后直接停止累加
	//同时这题要记录每次用的元素list
	public static void main(String[] args) {

	}
	public List<Integer> minSubsequence(int[] nums) {
		List<Integer> ans = new ArrayList<Integer>();
		int pre = 0;
		int next = 0;
		int all = 0;
		Arrays.sort(nums);
		for(int i = 0; i < nums.length; i++) {
			all += nums[i];
		}
		for(int i = nums.length-1; i >= 0; i--) {
			pre += nums[i];
			ans.add(nums[i]);
			if(pre > all-pre) {
				return ans;//ans
			}
		}
		return ans;
	}
}

第二题【中等】
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’

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/number-of-steps-to-reduce-a-number-in-binary-representation-to-one
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

错误原因:int num = Integer.valueOf(s, 2);数字太大了超过int的范围。BigInteger不够熟练。

BigInteger num = new BigInteger(s,2);
		BigInteger a = BigInteger.valueOf(2);
		int step = 0;
		while(!num.equals(BigInteger.ONE)) {
			step++;
			if(num.mod(a).equals(BigInteger.ZERO)) {
				num = num.divide(a);
			}else {
				num = num.add(BigInteger.ONE);
			}
		}
		return step;

其他方法:
//method2
//1、根据最后一个数是1,则这个二进制为奇数,奇数则加1,根据二进制的性质,将1->0,101->110后面的数依次将1变为0,直到遇到0,将这
//个0置为1后停止,如果直到最后都没有遇到0(111+1->1000)则说明结束,返回步数
//2、如果最后一个数是0,则说明该二进制是偶数,就左移110->1100

char c[] = s.toCharArray();
		int r = c.length-1;
		int re = r;
		int step = 0;
		while(r >= 1) {
			
			if(c[r] == '1') {
				step++;//加1的过程
				while(c[r] == '1') {
					step++;
					c[r] = '0';
					r--;
					if(r < 0) {
						return step;
					}
					
				}
				c[r] = '1';
			}
			if(c[r] == '0') {
				step++;//除以2
				//r--;
				if(--r == 0) return step;
			}
		}
		return step;
		

第三题 【中等】
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

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/longest-happy-string
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

错误原因:这道题要用到贪心算法写,因为我还没有开始练习贪心算法的题,相关题型做得比较少。之后是看了交流区的解法,然后结合自己现在能理解的写法解的。

解题思路:每次都放数目最多的字符,当放到两个或者该字符可放个数全部放完了,就放小一个字符,但是放下一个字符也要要求该字符的可放次数目前是最多的,这里就要处理一下,因为如果上一次放的字符的剩下可放次数可能也是最多个数或者与最多个数相等,那这里就要判断一下,然后继续放字符,直到无法放就结束。判断结束的条件是:有两种字符已经放完,而剩下一种字符连续放不能超过三个;或者三种字符都放完。

解题步骤:(交流区给出的解法是用构造函数将,字符和对应个数联系在一起,因为我构造函数学得不是很好,就换了一种方法)
1、创建ch数组存入的是字符’a’,‘b’,‘c’;创建lens[]数组,存入的是当前每种字符能放的个数;字符和其能被放的次数一一对应
2、创建StringBuilder,存每次放入的字符
3、放字符之前每次都要判断当前哪个字符的可放个数最多,从大到小排序,同时对应的字符也要跟着换位置
4、放字符时要判断当前能不能放(也就是判断上一个字符有没有超过两个连续,或者这个字符的个数有没有被放完)
5、最后返回StringBuilder对象,要转化成String
(因为我们学校Java还没有开始教,我的基础不是很扎实,这也是好多题解不出来,没有别人解得好的原因,哈哈)

package _183leetcode周赛;

public class _03最长字符串self {
	public String longestDiverseString(int a, int b, int c) {
		char[] ch = {'a', 'b', 'c'};
		StringBuilder sb = new StringBuilder();
		int lens[] = {a,b,c};
		while(true) {
			for(int i = 0; i < 2; i++) {
				for(int j = i+1; j < 3; j++) {
					 if(lens[j] > lens[i]) {
						 int t = lens[j];
						 lens[j] = lens[i];
						 lens[i] = t;
						 
						 char s = ch[j];
						 ch[j] = ch[i];
						 ch[i] = s;
					 }
				}
			}
			if(sb.length() >= 2 && 
					sb.charAt(sb.length()-1) == ch[0] && 
					sb.charAt(sb.length()-2) ==  ch[0]) {
				if(lens[1]-- > 0) {
					sb.append(ch[1]);
					
				}else {
					break;
				}
			}else {
				if(lens[0]-- > 0) {
					sb.append(ch[0]);
				}else {
					break;
				}
			}
		}
		return sb.toString();
	}
}
	

第四题【hard】
1406.石子游戏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

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/stone-game-iii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

错误原因:我直接按照取球博弈的基本思想写的,结果最优取法的考虑出错了,最后的测试用例134/185,题解中给出的解答基本上都是用动态规划做的,又是我太菜,哈哈。这题的类型说是:零和博弈,自己最优的时候,对手最差,哈哈。
考虑漏掉的:这道题的要求是每次都考虑最优取法,也就是,那Alice做例子:Alice在选这三堆石子如何取时,她不仅要考虑自己如何取到最多,也要考虑对手下一步取的话会不会比她多,比如:石子堆的对应得分是[-1,-2,-3],如果Alice只考虑自己取的得分最高,那她肯定取第一堆-1,但是当Bob来取时,他也会这样考虑,就会取-2,这样剩下最后一堆是-3,Alice不得不取走-3,则Alice输掉,但是实际答案是Tie平,因为Alice的最优解法是尽量赢,赢不了就逼平,所以她取的是-1,-2,Bob取的是-3;

解题思路:所以这道题动态规划解法思路是:dp[]中考虑是最优取法不是对应的人,因为第一个取的人,拿石子堆的方式都是让自己拿到得分最高且让对手面临的局面是尽量的差,但是在拿石子堆的过程中,先手变后手,后手变先手,所以dp每次面临的都是最优取法,所以不必要区分人,但是是不同人的最优解法,所以相当于最后dp得到的就是Alice的最优解法,总和减去Alice得分总和就是Bob的最优得分,从而判断结果。
这道题我吃得不透,还需要再琢磨,石子堆I,II,III下周练动态规划的时候会一起做。
题解看的是:
作者:Time-Limit
链接:https://leetcode-cn.com/problems/stone-game-iii/solution/ling-he-dui-shou-cai-qu-zui-you-de-fen-zui-shao-sh/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
作者:orangex
链接:https://leetcode-cn.com/problems/stone-game-iii/solution/shi-zi-you-xi-3jing-shen-fen-lie-ji-ke-by-orangex/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

class Solution {
    public String stoneGameIII(int[] stoneValue) {
		int n = stoneValue.length;
		int[] dp = new int[n+1];
		dp[n] = 0;
		int sum = 0;
		for(int i = n-1; i >= 0; i--) {
			dp[i] = dp[i] = Integer.MIN_VALUE;//每次都是一次重新的三堆选择
			sum += stoneValue[i];
			for(int j = i; j < i+3 && j < n; j++) {
				dp[i] = Math.max(dp[i], sum-dp[j+1]);
			}
		}
		if(sum - dp[0] == dp[0]) {
			return "Tie";
		}else if(sum - dp[0] > dp[0]){
			return "Bob";
		}
		return "Alice";
	}
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值