快慢指针法、双指针法、滑动窗口法

一、快慢指针法:

快慢指针法是一种十分常用的方法,其对于判断链表等是否具有无限循环的情况十分简单方便。
例如:现具有一个1,2,3,4,5,1,2,3,4,5…的无限循环的链表情况(链表的尾5指向链表的头1的情况),可以定义一个快指针,一个慢指针,初始两个指针都指向第一个1,让慢指针每次向后移一个节点,让快指针每次后移两个节点,在不断循环中最终两个指针都会指向相同节点位置的1,即如果存在循环,最终快慢指针会相遇,但若没有无限循环的情况,则快指针会提前到达终止条件,例如:现有一个链表:1,2,3,4,5 定义快慢指针各一个,慢指针一次后移一个节点,快指针一次后移两个节点,最终快指针会提前指向NULL到达终止条件,快慢指针不会相遇。
例题一:在这里插入图片描述
在这里插入图片描述
思考:(快慢指针法),先将链表节点只有一个或没有节点的特殊情况放在代码开头返回false,然后定义struct ListNode*类型的t1和t2两个指针,初始化都为head,然后建立while循环,每次让t1后移一个节点,让t2后移两个节点,如果是环形链表t1和t2最终会相遇,如果不是环状链表,t2会先指向NULL出while循环,若出while循环就返回false,如果在while循环中t1 == t2,就返回true

代码:

bool hasCycle(struct ListNode *head) {
    if (head == NULL || head -> next == NULL) {
        return false;
    }
    struct ListNode *t1 = head, *t2 = head;
    while (t2 != NULL && t1 != NULL) {
        t1 = t1 -> next;
        if (t2 -> next != NULL) {
            t2 = t2 -> next -> next;
        } else {
            t2 = NULL;
        }    
        if (t2 == t1) {
            return true;
        } 
    }
    return false;
}

例题二:
在这里插入图片描述

思考:(快慢指针法)slow(慢指针)每往后算一次,fast(快指针)就往后算两次,如果是快乐数的话,fast会先到1,slow会后到1,return的值就会为真,如果不是快乐数,fast会在不断的循环中与slow相遇(即值会相等)且值都不会为1,return的值就会为假

代码:

int jack(int n) {
    int t1, sum = 0;
    while (n) {
        t1 = n % 10; 
        sum += t1 * t1; 
        n /= 10;
    }
    return sum;
}

bool isHappy(int n){
    int slow = jack(n), fast = jack(jack(n));
    while (slow != fast) {
        slow = jack(slow);
        fast = jack(jack(fast));
    }
    return slow == 1;
}

二、双指针法:

双指针法一般常用于对与数组的处理,大体思路是定义一个左指针left,再定义一个右指针right,让两个指针分别从数组的两端按所需要求循环处理,最终实现所需的结果。
简单例子:要逆序一个数组或字符(例如数组和字符为a[]),只需要在满足条件left < right的条件下,交换a[left]和a[right],每次交换完后left加一、right减一,出循环时就可实现所需结果。
例题一:
在这里插入图片描述
在这里插入图片描述
思考:
(双指针法)定义一个快指针fast一个慢指针slow,当slow <= fast时执行循环,如果nums[fast]的值等于val那就fast减一,如果nums[slow]的值不等于val那就slow加一,当nums[fast] != val 且 nums[slow] == val时将nums[fast]的值赋给nums[slow],且让slow加一,fast减一,出循环后返回新数组的长度slow即可。

代码:

int removeElement(int* nums, int numsSize, int val){
    if (nums == NULL || numsSize == 0)
    return 0; 
    int slow = 0,fast = numsSize - 1;
    while (slow <= fast) {
        if (nums[fast] == val) {
            --fast;
            continue;
        }
        if (nums[slow] != val) {
            ++slow;
            continue;
        }
        nums[slow] = nums[fast];
        ++slow;
        --fast;
    }
    return slow;
}

例题二:
在这里插入图片描述
在这里插入图片描述
思考:(双指针法)left指向最左边,right指向最右边,i初始化为0,建立for循环(循环进行的条件是i <= right),用i遍历一遍数组,i只遇到0或2时才交换,i遇到2时和right交换,然后让right减一,z在while循环中将所有的2都放在最后面,出while循环后判断交换后的nums[i]是否等于0,等于0时与left交换(left只回为1,因为0已经被++left放在不会被操作的最前头了),然后让left加一,i遇见1时不做处理,当出for循环时,0都在1的左边,2都在1的右边,返回数组名nums即可。

代码:

void sortColors(int* nums, int numsSize){
    int left = 0, right = numsSize - 1, i, t;
    for (i = 0; i <= right; ++i) {
        while (i <= right && nums[i] ==2) {
            t = nums[right];
            nums[right] = nums[i];
            nums[i] = t;
            --right;
        }
        if (nums[i] == 0) {
            t = nums[left];
            nums[left] = nums[i];
            nums[i] = t;
            ++left;
        }
    }
    return nums;
}

三、滑动窗口法:

滑动窗口法常用于处理数组等相关问题,可以用时间复杂度o(n)和空间复杂度o(1)去实现一些操作,是简化数组操作的算法中的一种。
例题:
在这里插入图片描述
在这里插入图片描述
思考:滑动窗口法)先将特殊情况放在开头返回,定义两个指针start和end,初始都为0,分别表示子数组的开头和结尾,定义sum初始化为0,用来存储从start到end之间的子数组元素的和,每一轮迭代将nums[end]加到sum,如果sum >= s,则更新子数组的最小长度(此时子数组的最小长度是end - start + 1),然后将nums[start]从sum中减去并将start右移,直到sum < s,在此过程中同样更新子数组的最小长度。在每一轮迭代的最后,将end右移

代码:

int minSubArrayLen(int target, int* nums, int numsSize){
    if (numsSize == 0) {
        return 0;
    }
    int cnt = numsSize + 1, start = 0, end = 0, sum = 0;
    while (end < numsSize) {
        sum += nums[end]; 
        while (sum >= target) {
            cnt = fmin(cnt, end - start + 1);
            sum -= nums[start];
            ++start;
        }
        ++end;
    }
    return cnt == numsSize + 1 ? 0 : cnt;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值