🔻1.轮转数组

思路:
我们首先想到的方法是先创立一个新数组,再遍历元素,然后计算当前元素轮转后的位置,最后将其放入新数组,再进行下一个元素。我们之所以这样做是为了防止当前元素覆盖轮转位置上的元素。即是否有一个方法,可以暂时储存在轮转位置元素的值和其轮转位置。因为当前元素计算后的位置与轮转元素位置相同,所以我们只需要引入新变量记住它的值,再将当前元素轮转,此时位置正是轮转元素的位置
答案:
void rotate(vector<int>& nums, int k) {
int num=nums.size();
k=k%num;
for(int i=0;i<gcd(num,k);i++){
int current=i;
do{
int next=(current+k)%num;
swap(nums[current],nums[i]);
current=next;
}while(current!=i);
}
}
难点:如何用更简便的方法记住轮转元素的位置以及值是本题难点。利用当前元素计算后得到的位置=轮转位置这个容易被忽略的点,再引入新变量记住轮转元素的值是关键。
🔻2.移动零
给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序
请注意 ,必须在不复制数组的情况下原地对数组进行操作。
示例 1:
输入: nums = [0,1,0,3,12]输出:[1,3,12,0,0]
思路:将遇到的0与下一个非0的值进行交换,直到数组的最后一个元素
答案:
void moveZeroes(vector<int>& nums) {
int n = nums.size();
int begin = 0;
int end=0;
while(end!=n){
if(nums[end]){
swap(nums[begin],nums[end]);
begin++;
}
end++;
}
}
知识点:
双指针,运用左右双指针,左指针指向0,右指针指向非0的数,直到数组末尾
🔻3.链表的中间节点
给定一个头结点为 head 的非空单链表,返回链表的中间结点。
如果有两个中间结点,则返回第二个中间结点。
示例 1:
输入:[1,2,3,4,5]
输出:此列表中的结点 3 (序列化形式:[3,4,5])
思路:首先最容易想到先遍历到链表末尾,得到结点数,结点数除以2,再遍历到中间结点。那么有没有只用一次遍历就可以找到中间结点方法的呢?难点在于“中间”,如何在一次遍历中,就能知道结点总数,并处于中间位置呢?因为链表是单向的,所以我们就需要两个结点,一个计算总数,一个位于中间结点。只遍历一遍,即当一个指针到末尾时,另一个指针刚好位于中间。
答案:
ListNode* middleNode(ListNode* head) {
ListNode*slow=head;
ListNode*fast=head;
while(fast != NULL&&fast->next != NULL )
{
fast=fast->next->next;
slow=slow->next;
}
return slow;
}
知识点:
双指针,快慢指针,通过两个指针不同的行进速度来区分两个指针,在一次遍历中,到达两个不同位置
总结
这周主要学了双指针的运用。在对数组,链表进行调换,删除等有关顺序的操作时,可考虑使用双指针,节省时间。而不仅仅局限在一个指针上。通过增加指针的数量,以不同的条件区分,来换取时间