昨天腾讯笔试题:n个整数的圆环中取m个数,不能取相邻的,求可取出的最大和,同学提醒是LeetCode#213相似题目。
#213是#198的变式,所以又做了一下198. House Robber
// dp数组
class Solution {
public:
int rob(vector<int>& nums) {
int length = nums.size();
if(length == 0) return 0;
if(length == 1) return nums[0];
vector<int> dp(length, 0);
dp[0] = nums[0];
dp[1] = max(nums[0], nums[1]);
for(int i=2; i<length; i++) {
dp[i] = max(nums[i]+dp[i-2], dp[i-1]);
}
return dp[length-1];
}
};
// 两个变量代替dp数组,Runtime变快了一半
class Solution {
public:
int rob(vector<int>& nums) {
int length = nums.size();
if(length == 0) return 0;
if(length == 1) return nums[0];
// length==2, i==1
int minus2 = 0;
int minus1 = nums[0];
int current = max(nums[0], nums[1]);
for(int i=2; i<length; i++) {
minus2 = minus1;
minus1 = current;
current = max(nums[i]+minus2, minus1);
}
return current;
}
};
相比于#198,加了一步把圆圈化成直线,转换为#198.代码比较简单,max(选第一个, 不选第一个)。我称为“化圈为直法”。
class Solution {
public:
int rob(vector<int>& nums) {
int length = nums.size();
if(length == 0) return 0;
if(length == 1) return nums[0];
return max(rob(nums, 0, length-2), rob(nums, 1, length-1));
}
// 去环后
int rob(vector<int> nums, int low, int high) {
if(low == high) return nums[low];
vector<int> dp(high+1, 0);
dp[low] = nums[low];
dp[low+1] = max(nums[low], nums[low+1]);
for(int i=low+2; i<=high; i++) {
// 选nums[i]或不选
dp[i] = max(nums[i] + dp[i-2], dp[i-1]);
}
return dp[high];
}
};
感想:首先说说腾讯笔试感想。笔试前准备不足,比较仓促,笔试开始时脑袋空空连题目都看不进去,对输入输出语法也不太明白,后面更是有一道题测试用例没转过来弯。对于这种情况以后要避免,要保持每天写点代码的状态,笔试前时间要宽松,做好心理准备。很多题目稍微复杂就会产生恐惧心理,还是因为基本功不扎实,要多做题+温故知新。
用半个小时做出了第一道剑指Offer上几乎原题的约瑟夫环问题,心态好了一点点。后面的一个半小时来回看后面题目。第二道题题目虽长但是并不复杂,在最后求逐步增长数组的第k小,k也逐步++,不知道怎么解决,用了复制、sort函数。超时,case过了80%,不知道这种情况怎么给分。
再说这道题,是动态规划,也考虑到了动态规划,但是因为还不够熟练所以思考不清楚。
LeetCode这道题的所得:
1.化圈为直
3.对于输入的简单特殊情况处理,可能会重复,没关系,先写上,大不了就是代码不简洁问题,到最后再改善。
4.边界条件的处理很多时候跟越界访问有关,如果不处理边界很容易导致错误。
2.Math是Java的东西,c++取最大值只需要max(x1, x2)