领釦网算法学习笔记
本系列的算法题目来自领釦网
数组类算法第一天
题目:
给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素最多出现两次,返回移除后数组的新长度。
示例:
给定 nums = [1,1,1,2,2,3],
函数应返回新长度 length = 5, 并且原数组的前五个元素被修改为 1, 1, 2, 2, 3 。
给定 nums = [0,0,1,1,1,1,2,3,3],
函数应返回新长度 length = 7, 并且原数组的前五个元素被修改为 0, 0, 1, 1, 2, 3, 3 。
说明:
- 不要使用额外的数组空间,
- 你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。
解题过程:
思路:
根据之前的题目,看到这个题目的第一感觉是:我只要判断是的第几个重复值就OK了。
定义一个变量用来记录当前是第几个重复值,如果当前两个判断的值是一样的,且为这个变量的值为0,则保存这两个值,把这个变量的值改为1,后续判断时,因为这个变量值为一,所以重复值会忽略,当遇到两个不同的值时,则保存数据,且把这个变量的值变回0.
代码如下:
class Solution {
public int removeDuplicates(int[] nums) {
// 思路:定义一个变量用来记录当前是第几个重复值,如果当前两个判断的值是一样的,且为前两个则改变这个变量的值
// 如果当前变量的值改变了,则接下来的相同的数据就忽略掉
if(nums.length==0 || nums.length==1){
return nums.length;
}
int repeatNum = 0; // 如果repeatnum为0,则表示为前两个值,此时改变repeatNum值,当判断的值变化时在变回去
int numDate = 0; // 保存新数组的位置
for(int i=1;i<nums.length;i++){
if(nums[numDate]==nums[i] && repeatNum == 0){
numDate++;
nums[numDate] = nums[i];
repeatNum = 1;
}
if(nums[numDate]!=nums[i]){
numDate++;
nums[numDate] = nums[i];
repeatNum = 0;
}
}
return (numDate+1);
}
}
// 用时15ms
后续思考:
该方法我觉得已经很简便了,只需要循环一次数组且不会多次修改比较值,但是还不是最优的,最优的方法在不看优质解答的情况下真没思路了,证明思维还是有所欠缺的。
领釦上面该题其他高质量范例:
class Solution {
public int removeDuplicates(int[] nums) {
int i = 0;
for (int num : nums) {
if (i < 2 || num > nums[i - 2]) {
nums[i++] = num;
}
}
return i;
}
}
// 用时 <1ms
自我整理:
- 这个代码,不能说惊艳到我了,毕竟只有短短的这一段,但是这个思路很值得我借鉴。
思路:
因为要重复值最多保留两个,所以只要现在的值和第三个的值不一样就可以了。不管第二个值相不相同。
class Solution {
public int removeDuplicates(int[] nums) {
if(nums.length==0 || nums==null) return 0;
int k = 0;
int count = 0;
for(int i=0; i<nums.length; i++){
if(i==0 || nums[i] != nums[i-1]) count = 0;
else count ++;
if(count<=1){
nums[k++] = nums[i];
}
}
return k;
}
}
// 用时2ms
自我整理:
用时1ms的代码只是比小于1ms的代码多了个数据长度判断,思路是一样的。所以没写,
2ms这个思路其实也是一个方向吧,但是感觉没有像上一个那样新奇,思路还是比较大众的。
思路:
它依然是定义一个变量来记录当前重复值的数量,根据变量的值来判定是否保留。
自我总结:
其实很多时候,看着题目,我们需要发散一下思维,想一下都有哪些情况能达到题目的要求,不要侷限于一般的逻辑思维,可能目前的思维比较差,但是我觉得遇到问题时,在你很快能想到一个普遍的想法时,或许可以再多抽点时间想想有没有更好的方法。就算没有,发散一下思维,也能锻炼一下自己,使得下一次思维的扩展性变得更好。