2.双指针

双指针使用条件

0.总结:
--- 有两个数组或者链表的,
--- 或者一个数组但是要求让你干的事可以从首尾一起干的,
--- 又或者一个数组,可以从中间和两端都一起干的那种,都可以用双指针
1.腚眼一瞅,可以从两边往里搞那种,比如:11
2.链表奇奇怪怪,题目有俩链表那种:160,一根链表也问:876,估计也就这一道题
3.链表有环的:141142
4.要求原地操作,只可以使⽤交换,不能使⽤额外空间: 344
5.有的时候你想的话,也有三个指针的,比如:面试题 10.01886.还有的是双指针指在左右和中间动态的k上比如:189,题目中的特殊的值作为指针
7.指针是动态再加动态:15

例题

1)141. 环形链表

var hasCycle = function (head) {
    //设置快慢指针
    let slow = head,fast = head;
    //如果没有环,则快指针会抵达终点,否则继续移动双指针
    while (fast && fast.next) {
        slow = slow.next;
        fast = fast.next.next;
        //快慢指针相遇,说明含有环
        if (slow == fast) {
            return true;
        }
    }
    return false;
};

2)142. 环形链表 II

// 这个题需要用数学先算一下
// 相遇时
//1.fast = 2slow (快指针每次2步,路程刚好2倍)
//2.fast = slow + nb(相遇时,刚好多走了n圈)
//推出:slow = nb
//从head结点走到入环点需要走 : a + nb, 而slow已经走了nb,那么slow再走a步就是入环点了。
var detectCycle = function(head) {
    let fast = head, slow = head;
    while (fast) {
    	// if的条件,判断快指针
        if (fast.next == null) return null;
        fast = fast.next.next;
        slow = slow.next;
        if (fast == slow) { // 这个的判断条件是两个等于号
            fast = head;
            while (fast !== slow){
                fast = fast.next;
                slow = slow.next
            }
            return fast
        }
    }
    return null
};

3)15. 三数之和

var threeSum = function (nums) {
    let ans = [];
    let len = nums.length;
    if (len < 3)  return ans;
    nums.sort((a, b) => a-b); // 排序别忘了
    for (let i = 0; i < len; i++) {
        if (nums[i] > 0) return ans;
        // 去重
        if (nums[i] == nums[i - 1]) continue // i+1不行 会越界  i-1 行  因为没有就没有呗
        let l = i + 1; // l一开始是固定的,后边动态改变
        let r = len - 1;
        while (l < r) {
            let sum = nums[i] + nums[l] + nums[r];//这个写在while里边
            if (sum == 0) {
                ans.push([nums[i], nums[l], nums[r]])
                // 当找到一个sum=0之后,去重,左边右边
                while (nums[l] == nums[l + 1]) l++ ;//l++不是continue
                while (nums[r] == nums[r - 1]) r-- ;//r--不是continue
                // i一个值 可能对应 多个 sum = 0 的情况
                l++;
                r--;
            } 
            else if (sum < 0) l++;
            else if (sum > 0) r--;
        }
    }
    return ans
};

4)11. 盛最多水的容器

var maxArea = function (height) {
    // 这道题思路开始的地方是,双指针,从两边往里使劲
    // 下边应该用while循环,所以并不是所有知道长度的就for循环
    // 往中间前进的条件:谁小,不要谁
    let i = 0, j = height.length - 1; ans = 0;
    while (i < j) {
        let tmp = Math.max(ans, (j - i) * (Math.min(height[i], height[j])))
        if (height[i] < height[j]) {
            ans = tmp;
            i++;
        } else if (height[i] >= height[j]) {
            ans = tmp;
            j--;
        }
    }
    return ans
};

5)160. 相交链表

var getIntersectionNode = function(headA, headB) {
	//https://leetcode.cn/problems/intersection-of-two-linked-lists/solution/intersection-of-two-linked-lists-shuang-zhi-zhen-l/
    // 这道题利用的就是俩链表长度不相等 解出来的
    if (headA == null || headB == null) {
        return null
    }
    let a = headA, b=headB; 
    while (a !== b) {
        a = a === null ? headB : a.next;
        b = b === null ? headA : b.next; 
    }
    return b
};

6)876. 链表的中间结点

var middleNode = function(head) {
    // 我想的1.头部和尾部两个指针,但是链表不可以反着来
    // 2.这要是中间节点能找到,其他不是都能找到么,(原来本题是取巧,却也满足)
    let slow= head, fast = head;
    while(fast && fast.next){
        slow = slow.next;
        fast = fast.next.next;
    }
    return slow
};

7)344. 反转字符串

var reverseString = function(s) {
    // 不看答案唯一能想到的就是遍历,俩指针,互换位置那种
    // tm 答案也是这么做的 淦 啊
    let l = 0, r = s.length - 1;
    while(l < r){
        [s[l], s[r]] = [s[r], s[l]]
        l++
        r--
    }
    return s
};

8)125. 验证回文串

var isPalindrome = function (s) {
    s = s.toLowerCase();
    let l = 0, r = s.length - 1;
    while (l < r) {
        if (!isValid(s[l])) { l++; continue };
        if (!isValid(s[r])) { r--; continue };
        if(s[l] != s[r]) return false;
        l++;
        r--;
    }
    return true

};
var isValid = function (char) {
    return  (char >= "a" && char <= "z") || (char >= "0" && char <= "9")
}

9)392. 判断子序列

var isSubsequence = function(s, t) {
    let n = s.length, m = t.length;
    let i = 0, j = 0;
    while(i < n && j < m){
        if(s[i] == t[j]) i++;
        j++
    }
    return i == n
};

10)88. 合并两个有序数组:这个和下边的一样

var merge = function (nums1, m, nums2, n) {
// https://leetcode.cn/problems/sorted-merge-lcci/solution/tu-jie-shuang-zhi-zhen-yuan-di-xiu-gai-by-z1m/
    let m1 = m - 1, n1 = n - 1, cur = n + m - 1;
    while (m1 > -1 && n1 > -1) {
        if (nums1[m1] >= nums2[n1]) {
            nums1[cur] = nums1[m1];
            cur--;
            m1--;
        } else if (nums1[m1] < nums2[n1]) {
            nums1[cur] = nums2[n1];
            cur--;
            n1--;
        }
    }
    if (n1 != -1) {
        for (let i = 0; i <= n1; i++) {
            nums1[i] = nums2[i]
        }
    }
    return nums1
};

11)75. 颜色分类,什么样的脑袋瓜才能想出这样的答案呢

var sortColors = function (nums) {
    //    [2 0 2 1 1 1 0] 
    // -> [2 2 2 2 2 2 2] 先全填上2
    // -> [1 1 1 1 1 2 2] 统计下0和1的个数之和(作为数字1的右侧边界),然后填上1
    // -> [0 0 1 1 1 2 2] 统计下0的个数(作为数字0的右侧边界),然后填上0

    // https://leetcode.cn/problems/sort-colors/solution/java100-94-yi-ci-bian-li-by-jade_xie-v5tl/

    let zero = 0, one = 0, two = 0;
    for (let i = 0; i < nums.length; i++) {
        let tmp = nums[i];
        nums[two++] = 2;
        if (tmp <= 1) {
            nums[one] = 1;
            one++;
        }
        if (tmp == 0) {
            nums[zero] = 0;
            zero++;
        }
    }
};

12)283. 移动零

var moveZeroes = function (nums) {
    // 遍历数组,不为0的元素移动数组前方,用index下标记录。
    // 遍历结束,对index值后的元素统一设为0
    let index = 0;
    for (let i = 0; i < nums.length; i++) {
        if (nums[i] != 0) {
            nums[index] = nums[i];
            index++
        }
    }
    while (index < nums.length) {
        nums[index] = 0;
        index++
    }
};

13)189. 轮转数组

var rotate = function (nums, k) {
    // https://leetcode.cn/problems/rotate-array/solution/by-lyl-8b-pyy2/
    // 旋转三次
    rotateArr(nums, 0, nums.length - 1);
    k = k % nums.length;
    rotateArr(nums, 0, k-1);
    rotateArr(nums, k, nums.length - 1);
    return nums

};

var rotateArr = function (nums, start, end) {
    while (start < end) {
        [nums[start], nums[end]] = [nums[end], nums[start]];
        start++;
        end--;
    }
    return nums
}

14)面试题 10.01. 合并排序的数组

// 解法1:双指针
var merge = function (A, m, B, n) {
    for (let i = m; i < m + n;i++){
        A[i] =B[i-m]
    }
    A.sort((a, b) => a - b)
};
// 解法2:三指针
var merge = function (A, m, B, n) {
var merge = function (A, m, B, n) {
    // https://leetcode.cn/problems/sorted-merge-lcci/solution/tu-jie-shuang-zhi-zhen-yuan-di-xiu-gai-by-z1m/
    let m1 = m - 1, n1 = n - 1, cur = m + n - 1;
    while ((m1 > -1) && (n1 > -1)) {
        if (A[m1] >= B[n1]) {
            A[cur] = A[m1];
            cur--;
            m1--;
        } else if (A[m1] < B[n1]) {
            A[cur] = B[n1];
            cur--;
            n1--;
        }
    }
    if (n1 != -1) {
        // 下边这个是小于等于
        for (let i = 0; i <= n1; i++) {
            A[i] = B[i]
        }
    }
    return A
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值