引言
有些关于数组的题目说难不难,说简单的话也非常不简单,如果稍微在数组操作中加一些限制条件,比如时间复杂度只能是O(n),空间复杂度只能是O(1)或者O(n),那么这样的题就跟数学题和智力题一样很考验人。
类似题目
leetcode-645 错误的集合;leetcode-442 数组中重复的元素;
解题思路:
刚开始的时候,我之前都是第一印象是对原来数组进行排序,这样一来数组中的数据假如题目中给的数据是【1-n】的话,那么大概可以各自归位了,即nums[i]=i+1.但是呢,这样的方法是不可取的,一是因为假如重复的数如果在排序之后并不是挨着的,例如LeetCode-645中的一个测试用例【3,2,3,4,6,5】,重复的3和缺少的1就没有挨着。所以经过查看网上大神们的做题思路,感觉很新奇:
他们并不是对原来的数据进行修改,而是对其符号进行修改,遇到nums[i]那么就把下标为nums[i]-1的这个元素符号进行反转:
- 如果为正,那么就把下标为nums[i]-1的元素符号更换
- 如果为负,说明之前下标为nums[i]-1的元素已经存在了,那么就可以立马找到重复的那个数就是nums[i].就可以直接把重复的结果找到。
例如leetcode-645 错误的集合:参考https://blog.csdn.net/woshichaoren000/article/details/76147116的杰作:
vector<int> findErrorNums(vector<int>& nums) {
vector <int> ans;
for (int i = 0; i < nums.size(); i++) {
int index = abs(nums[i]) - 1;
if (nums[index] > 0) {
nums[index] *= -1;
}
else {
ans.push_back(index + 1);
}
}
for (int i = 0; i < nums.size(); i++) {
if (nums[i] > 0) {
ans.push_back(i + 1);
}
}
return ans;
}
就是我刚才说的思路。
leetcode-442使用相同的思路完全可以解决,而且时间复杂度只有O(N),空间复杂度只有O(1)。参考大神https://blog.csdn.net/bengepai/article/details/79200450的代码入下:
vector<int> findDuplicates(vector<int>& nums) {
vector<int> result;
for(int i=0;i<nums.size();i++)
{
nums[abs(nums[i])-1]=-nums[abs(nums[i])-1];//将当前值所对应的索引的值变为相反数。
if(nums[abs(nums[i])-1]>0)//大于0,说明该数变过2次,说明对应的索引出现了2次,索引即为重复数字(因为没有5,6所以他根本不会查看5,6的下标是否为正负,所以就可以解决,6,5对应下标也是正数的情况)
result.push_back(abs(nums[i]));
}
return result;
}
所以,当对简单数组操作的时候,有时候并不简单,稍微加一个限制条件就有可能难道一个新高度。所以参考那些大神的思路总会让我有一些感慨。世界之大,山外有山,天外有天呀。总会有新奇的方法来解决,只有不断的更新不断的发现,在慢慢迭代的过程中找到一个更好的解决问题的模型,这个不仅需要想法,感觉积累和经验也是非常重要的,好了,不嘚吧这么多了,经验总结到这里,希望看到的盆友们能够有所收获。
斯是陋室惟“汝”德馨!欢迎关注和交流。