【LeetCode算法学习笔记】双指针技巧(有更新)

labuladong算法公众号学习笔记

快慢指针的常见算法

链表中是否有环

boolean hasCycle(ListNode head){
    ListNode fast,slow;
    fast = slow = head;
    while(fast != null && fast.next != null){
        fast = fast.next.next;
        slow = slow.next;
        
        if(fast == slow) return true;
    }
    return false;
}

已知链表中有环,返回这个环的起始位置

ListNode detectCycle(ListNode head){
    ListNode fast,slow;
    fast = slow = head;
    while(fast != null && fast.next != null){
        fast = fast.next.next;
        slow = slow.next;
        if(fast == slow) break;
    }
    slow = head;
    while(slow != fast){
        fast = fast.next;
        slow = slow.next;
    }
    return slow;
}

第一次相遇时,若慢指针slow走了k步,则快指针走了2k步,即fast一定比slow多走了k步,而k的值一定是环长度的整数倍。
假设相遇点矩环的起点的距离为m,则环的起点距头结点head的距离为k-m。同时,如果从相遇的点继续前进k-m步也恰好到达环起点。所以只要我们把快慢指针中的任一一个重新指向head,两个同速前进,k-m步就会相遇,相遇出就是环的起点。

寻找链表中点

ListNode middleNode(ListNode head){
    ListNode fast,slow;
    fast = slow = head;
    while(fast != null && fast.next != null){
        fast = fast.next.next;
        slow = slow.next;
    }
    return slow;
}

当快指针到达链表尽头时,慢指针刚好处于链表中间。且如果链表长度为奇数,slow恰好停在中点的位置;如果为偶数,则slow的位置为中间偏右。

寻找链表第n个元素

还是使用快慢指针,先让快指针走n步,然后快慢指针同速前进,当快指针达到链表末端时,慢指针的位置刚好是第n个元素的位置。

ListNode removeNthFromEnd(ListNode head){
    ListNode fast,slow;
    fast = slow = head;
    while(n --> 0){//n --> 0意思是循环n次,还可以写为--n >= 0
        fast = fast.next;
    }
    if(fast == null){
        //如果此时快指针走到了头,则说明倒数第n个节点就是第一个节点
        return head.next;
    }
    //快慢指针同速前进
    while(fast != null && fast.next != null){
        fast = fast.next;
        slow = slow.next;
    }
    //slow.next就是倒数第n个节点,删除即可
    slow.next = slow.next.next;
    return head;
}

左右指针常用算法

左右指针在数组中是两个索引值,一般初始化为left = 0,right = nums.length - 1。

二分查找

int binarySearch(int[] nums,int target){
    int left = 0;
    int right = nums.length - 1;
    while(left != right){
        int mid = (right + left) / 2;
        if(nums[mid] == target) return mid;
        else if(nums[mid] > target) right = mid -1;
        else if(nums[mid] < target) left = mid + 1;
    }
    return -1;
}

两数之和

只要数组有序,就应该想到双指针,通过调节left和right可以调节sum的大小。

int[] twoSum(int[] nums,int target){
    int left = 0,right = nums.length - 1;
    while(left <right){
        int sum = nums[left] + nums[right];
        if(sum == target) return new int[]{left + 1, right + 1};//题目要求的索引是从1开始的。
        else if(sum < target) left++;//sum大一点
        else if(sum > target) right--;//sum小一点
    }
    return new int[]{-1,-1};
}

反转数组

void reverseString(char[] arr){
    int left = 0,right = arr.length - 1;
    while(left < right){
        //交换arr[left]和arr[right]
        char temp = arr[left];
        arr[left] = arr[right];
        arr[right] = temp;
        left++;right--;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值