题目1:
指路:
思路与分析:
最适合本题的当属摩尔投票法。摩尔投票法是在数组或序列中查找出现次数超过一半的主要元素的算法。其中,主要元素是指在数组中出现超过数组长度一半的元素。基本原理为不同元素之间相互抵消从而找出主要元素候选者,最后验证满足要求的候选者。其中,我们通过“投票”这一形式尝试找出众数,过程中,当遍历到的元素与查找元素相等时计数器+1,表示个数增多一个,反之-1。换言之,如果现在这个众数是a,它出现的次数大于其他元素出现次数的总和,那么它的票数足以对抗其他所有的元素票数得到正数票从而留在场上。
至于代码大家可以尝试或者看题解,我还没有完全写出来就不放了(LC题解中我推荐看第二个)。
题目2:
指路:
思路与分析:
通过题意与示例中的输入与输出我们不难看出数组的轮转规律,即将尾元素轮转到首位置,再把原首位置到原n-1位置的数组依次后移,重复k次,返回数组。在这里我们讨论一下轮转次数的问题。题目中并未说明k与n的大小关系,换言之,轮转次数与元素数量的大小关系不确定,分类讨论,当轮转次数>元素数量时,轮转k次会在中间轮转n次得到原数组(在这里暂且称为"无效轮转"),我们无需浪费资源得到初始数组,因此我们将k%n,得到的就是有效轮转次数。再精确一点,对于每个位置(用i代称)的轮转次数就是(i + k) % n。
代码:
1.开辟新的内存空间。
我们用一个新的内存空间vec作为中转场,盛放对应的数值,最后用assign将vec中的元素复制到原数组中即可(注意,assign用法多样,适用性广,建议单独查资料学习)。
class Solution {
public:
void rotate(vector<int>& nums, int k) {
int n = nums.size();
vector<int> vec(n);
for (int i = 0; i < n; i++) {
vec[(i + k) % n] = nums[i];
}
nums.assign(vec.begin(), vec.end());
// 复制vec中的全部元素到nums
}
};
2.reverse旋转
这个方法我确实没有考虑到,看到别人直接旋转秒掉一开始也是很诧异,但是细看之后觉得确实很妙。首先,对于k的处理等同于前面取余的操作,后面就开始翻转了。以给出的样例数组为例,原数组为[1, 2, 3, 4, 5, 6, 7],同时k=3,意思是数组轮转k次。最后得到的[5, 6, 7, 1, 2, 3, 4],不难看出维护一个大小为7的数组,同时使原数组内的每个元素都后移k位,最后的元素补到前面。那么对原数组翻转,得到第一步轮转,此时得到[7, 6, 5, 4, 3, 2, 1],除了新得到的首元素7外其他的元素都不符合轮转标准,那么对得到的数组进行从首元素7到k位置元素5的翻转也就是[5, 6, 7, 4, 3, 2, 1],此时完成了k位置以前元素的翻转,最后将k位置以后的元素翻转即可,得到[5, 6, 7, 1, 2, 3, 4]。好厉害,学会了。
class Solution {
public:
void rotate(vector<int>& nums, int k) {
int n = nums.size();
k %= n;
reverse(nums.begin(), nums.end());
reverse(nums.begin(), nums.begin() + k);
reverse(nums.begin() + k, nums.end());
}
};