Leetcode刷题 2021.02.11
Leetcode306 累加数
累加数是一个字符串,组成它的数字可以形成累加序列。
一个有效的累加序列必须至少包含 3 个数。除了最开始的两个数以外,字符串中的其他数都等于它之前两个数相加的和。
给定一个只包含数字 ‘0’-‘9’ 的字符串,编写一个算法来判断给定输入是否是累加数。
说明: 累加序列里的数不会以 0 开头,所以不会出现 1, 2, 03 或者 1, 02, 3 的情况。
大年三十的晚上还在写博客,/(ㄒoㄒ)/~~,马上十二点了,还是赶紧写吧, 新年愿望就是拿一个大厂的offer。
题目本身是比较基础的回溯做法,但是有各种边界情况要考虑,提交了好多次才通过。
class Solution {
public boolean isAdditiveNumber(String num) {
if(num.length() < 3) return false;
//前两位是一定成立的,所以可以初始化前两位是负数
return helper(num, 0, -1, -1, 0);
}
private boolean helper(String num, int index, long prev1, long prev2, int count){
//如果超过边界,并且数目大于等于三就返回true
if (index >= num.length() && count >= 3){
return true;
}
//long防止数字过大
long now = 0;
for(int i = index; i < num.length(); i++){
//获取当前的数字
now = now * 10 + num.charAt(i) - '0';
if (num.charAt(index) == '0' && now != 0) return false;
//如果数目小于二,或者相等就继续递归
if ((count < 2 || prev1 + prev2 == now) && helper(num, i + 1, prev2, now, count + 1)){
return true;
}
}
return false;
}
}
LeetcodeLCP12 小张刷题计划
为了提高自己的代码能力,小张制定了 LeetCode 刷题计划,他选中了 LeetCode 题库中的 n 道题,编号从 0 到 n-1,并计划在 m 天内按照题目编号顺序刷完所有的题目(注意,小张不能用多天完成同一题)。
在小张刷题计划中,小张需要用 time[i] 的时间完成编号 i 的题目。此外,小张还可以使用场外求助功能,通过询问他的好朋友小杨题目的解法,可以省去该题的做题时间。为了防止“小张刷题计划”变成“小杨刷题计划”,小张每天最多使用一次求助。
我们定义 m 天中做题时间最多的一天耗时为 T(小杨完成的题目不计入做题总时间)。请你帮小张求出最小的 T是多少。
又是二分查找基础题,不断地尝试缩小边界即可。
class Solution {
public int minTime(int[] time, int m) {
if (time.length <= m) return 0;
int i = 0, j = 1_000_000_000;
//二分模板
while (i < j){
int mid = i + (j - i) / 2;
if (helper(time, m, mid)){
j = mid;
}else{
i = mid + 1;
}
}
return i;
}
//这个可以转换为,求一段连续数组的最大值小于等于给定值,数组的一个元素可以忽略,所以肯定是忽略最大值,在遍历过程中记录即可。
private boolean helper(int[] time, int m, int target){
int n = time.length, sum = 0, max = 0, count = 0, i = 0;
while (i < n){
sum += max + time[i];
max = Math.max(max, time[i]);
sum -= max;
if (sum > target){
count++;
sum = max = 0;
}else{
i++;
}
if (count == m) break;
}
return i >= n ? true : false;
}
}
Leetcode673 最长递增子序列的个数
给定一个未排序的整数数组,找到最长递增子序列的个数。
O(n^2)的做法和最长递增子序列长度基本一致,只是需要另一个维度记录子序列的个数就行。
class Solution {
public int findNumberOfLIS(int[] nums) {
if (nums.length == 0) return 0;
int n = nums.length;
int[][] dp = new int[n][2];
//初始化为1
for(int i = 0; i < n; i++){
dp[i][0] = 1;
dp[i][1] = 1;
}
int max = 0;
for(int i = 0; i < n; i++){
for(int j = 0; j < i; j++){
//如果当前元素大于之前的元素
if (nums[i] > nums[j]){
//如果之前元素子序列的长度加1大于当前最长子序列,就更新一下子序列长度和个数
if (dp[j][0] + 1 > dp[i][0]){
dp[i][0] = dp[j][0] + 1;
dp[i][1] = dp[j][1];
//如果相等,就再加上子序列个数
}else if (dp[j][0] + 1 == dp[i][0]){
dp[i][1] += dp[j][1];
}
}
}
//记录一下最长子序列的长度
max = Math.max(max, dp[i][0]);
}
int res = 0;
//再遍历一次,把等于最长子序列长度的子序列数都加起来
for(int i = 0; i < n; i++){
if (dp[i][0] == max) res += dp[i][1];
}
return res;
}
}