算法之双指针

移除元素

代码报错原因,在快指针进行判断时没有判断是否超出边界。

j<nums.length

思想:使用快慢指针,初始化两个指针都指向第一个元素

  1. 当快指针==val值时,快指针后移一位,循环此操作;
  2. 当快指针!=val时,将快指针的值赋给慢指针,快慢指针皆往后移动一位
        int j=0;
        int i=0;
        while(j<nums.length){
            while(j<nums.length&&nums[j]==val){
                j++;
            }
            if(j<nums.length&&nums[j]!=val){
                nums[i]=nums[j];
                i++;
                j++;
            }
        }
        return i;

  

替换数字※

实现了replace的手动实现,但没有使用双指针法从后往前进行替换。

 StringBuffer strB=new StringBuffer(s);
        for (int i=0; i<strB.length();i++ ) {
            if (strB.charAt(i) <='9'&& strB.charAt(i)>='0'){
                String substring=strB.substring(i+1,strB.length());
                strB.setLength(strB.length()+5);
                strB.replace(i+6,strB.length(),substring);
                strB.replace(i,i+6,"number");
                i=i+5;
            }
        }
        System.out.println(strB.toString());
        

 

反转字符串中的单词

双指针的思想主要指删除空格,如果不用双指针,找到需要删除的每个元素是O(n),将后面的元素往前移需要O(n),复杂度为O(n2);

用双指针为O(n),思想和移除元素相同!!

int slowIndex=0;
        int fastIndex=0;
        while(fastIndex<strB.length() && strB.charAt(fastIndex)==' '){
            fastIndex++;
        }

        for(;fastIndex<strB.length();fastIndex++){
            if(fastIndex>0 && strB.charAt(fastIndex) == strB.charAt(fastIndex-1) && strB.charAt(fastIndex)==' '){
                continue;
            }else{
                strB.setCharAt(slowIndex,strB.charAt(fastIndex));
                slowIndex++;
            }
        }

        if(strB.charAt(slowIndex-1)==' '){
            strB.setLength(slowIndex-1);
        }else{
            strB.setLength(slowIndex);
        }

 

链表中删除第倒N个节点

报错原因:没有考虑到当N和链表节点个数相同时,此时end节点为null的情况

思路:使用快慢指针,快指针和慢指针间隔N-1个位置,当快指针到达尾节点时,慢指针=慢指针.next

查看代码
 public ListNode removeNthFromEnd(ListNode head, int n) {
        ListNode start=head;
        ListNode end=head;
        while(end !=null && n>0){
            end=end.next;
            n--;
        }
        if (end==null){
            return start.next;
        }
        while(end.next != null){
            end=end.next;
            start=start.next;
        }
        start.next=start.next.next;
    return head;
    }

 

链表相交

报错:1、Java中求绝对值的函数Math.abs()

           2、for循环的中间位置为判断是否满足该条件,满足则继续执行

           3、一开始想从尾往头判断是否相等(错误思想),因为链表的指针只指向后一个

           4、没有考虑存在链表为空的情况

思路:将指向长链表的指针向前移动,直到和短链表的头位置相同,然后就可以进行判断

public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        ListNode tailA=headA;
        ListNode tailB=headB;
        if(headA== null || headB ==null){
            return null;
        }
        int lengthA=1;
        int lengthB=1;
        while(tailA.next != null){
            lengthA++;
            tailA=tailA.next;
        }
        while(tailB.next != null){
            lengthB++;
            tailB=tailB.next;
        }

        tailA=headA;
        tailB=headB;
        for(int i=0;i<Math.abs(lengthA-lengthB);i++){
            if(lengthA>lengthB){
                tailA=tailA.next;
            }else{
                tailB=tailB.next;
            }
        }

        while(tailA != tailB && tailA.next != null && tailB!=null){
            tailA=tailA.next;
            tailB=tailB.next;
        }
        if(tailA == tailB){
            return tailA;
        }
        return null;
    }

 

环形链表相交※

首先明确快慢指针相交的点不一定是入环点,但相交点一定是环内的一点。

切入点:通过快慢指针步数的两倍关系,构建等式。根据等式得:快慢指针在环内相交之后从head开始和从相交点开始一起走,再相交的点为入环点!

使用while(fast.next!=null && fast!=null)判断不为环形链表

 

三数相加※

首先明确思想,外层为left循环,内层循环为mid和right大小判断。相当于将left作为锚点,对于每一个left值,mid和right在left+1和nums.legth-1中移动。

确保结果不重复的切入点:在内层循环外对nums[left]和nums[left-1](必须是和-1,不能是+1)进行相等判断,若相等continue(continue执行后,for中的left++依然执行!!!!!

            在内层循环内当三数相等时,循环判断nums[mid]==nums[mid+1],若成立则mid++,right同理。

Java函数基本用法:Arrays.asList(数组):将数组转为list

         list.add():向list中添加元素

 

总结

双指针可以用来移除和修改指定数组元素,因为数组元素不能被删除,只能被覆盖

双指针可以用来删除指定位置的链表元素,和解决链表相交的问题

双指针用来获得多数相加为指定值的情况,情况为具体值而不是在数组中的下标

 

 

posted @ 2025-02-05 10:01  Dyj07  阅读(25)  评论(0)    收藏  举报