leetcode刷题笔记之双指针

106 阅读2分钟

例题1: 两数之和

这题可以用双指针法和hashmap做。

用双指针做的话需要额外的时间开销是排序O(nlogn),需要注意点:

  • 返回的是原本数组的下标而非排序后数组的下标,所以要加一个遍历搜下标的方法getPos

  • 上述方法要注意数组中存在多个一样的数的情况,比如:

    [3,3] 6

        可以自己选择合适的方法避免这类情况。

代码如下:

class Solution {    public int[] twoSum(int[] nums, int target) {        if(nums.length<2) return null;        int left;        int right;        int[] result=new int[2];        //new一个数组进行排序        int[] sort=new int[nums.length];        System.arraycopy(nums,0,sort,0,nums.length);        Arrays.sort(sort);                for(left=0,right=sort.length-1;left<right; ){            int temp=sort[left]+sort[right];            if(temp==target){                result=getPos(nums,sort,left,right);                return result;            }            if(temp<target)left++;            if(temp>target)right--;        }        return null;            }    public int[] getPos(int[] nums,int[] sort,int left,int right){        int[] result=new int[]{-1,-1};        for(int i=0;i<nums.length;i++){            if(nums[i]==sort[left] && result[0]==-1) {                result[0]=i;            }else if(nums[i]==sort[right]) {                result[1]=i;            }        }        return result;    }}
执行用时:2 ms, 在所有 Java 提交中击败了99.60%的用户
内存消耗:40 MB, 在所有 Java 提交中击败了44.31%的用户

例题2:面试题 02.01. 移除重复节点

使用临时缓冲区的方法比较简单,比如采用hashmap然后通过是否存在key来移除或者保留节点,时间复杂度为O(n)。用双指针法就是两重循环,时间复杂度高,适合要求不采用临时缓冲区的方法,实现代码如下:

class Solution {    
    public ListNode removeDuplicateNodes(ListNode head) {
        //单向节点,只能从前到后遍历        
        if(head==null || head.next == null)return head;        
        ListNode node=head;        
        //要考虑改变head节点的next节点        
        ListNode headNext=null;         
        while(node!=null){           
            ListNode next=node;                    
            while(next.next!=null){                
                if(next.next.val==node.val){                    
                    next.next=next.next.next;                
                }else{                    
                    next=next.next;                  }                 
            }                    
            node=node.next;        
        }            
            return head;    
    }
}

要注意的是:

1.用node指向head之后,head.next不会因为循环而改变,所以需要一个node保存循环后head.next应该指向的值,否则{1,1,1,1,1,2}这类的数组输出结果是{1,1,2}。所以要从head开始判断,而不是直接从head.next开始判断和head是否一致(适用于所有单向链表);

2.删除的时候需要一个变量保存前节点来删除节点,要分析好next和next.next在值相等的时候指向哪里,不相等又指向哪里。

这是牺牲时间换空间的方法,所以执行用时就很不行。

执行用时:405 ms, 在所有 Java 提交中击败了6.11%的用户
内存消耗:40.7 MB, 在所有 Java 提交中击败了77.27%的用户

例题3: 977. 有序数组的平方

class Solution {    
    public int[] sortedSquares(int[] A) {        
    //双数组法从两边到中间        
    int left;        
    int right;        
    int[] squares=new int[A.length];        
    int i;        
    for(left=0,right=A.length-1,i=A.length-1;left<=right && i>=0;i--){            
        int l=(int)Math.pow(A[left],2);            
        int r=(int)Math.pow(A[right],2);            
        if(l>r){                
            squares[i]=l;                
            left++;            
        }else{                
            squares[i]=r;                
            right--;            
        }        
    }        
    return squares;    
    }
}

例题4:1300. 转变数组后最接近目标值的数组和

class Solution {public int findBestValue(int[] arr, int target) {        Arrays.sort(arr);        int sum = 0;        int ave = target / arr.length;        if (arr[0] > ave) {            double aveDou = (target * 1.0) / arr.length;            System.out.println(aveDou);            if (Math.abs(aveDou - ave) <= 0.5) {                return ave;            } else {                return ave + 1;            }        }        for (int i = 0; i < arr.length - 1; i++) {            sum += arr[i];            int curAve = (target - sum) / (arr.length - i - 1);            System.out.println("curAvue"+curAve);            System.out.println("i"+i);            if (curAve < arr[i + 1]) {                double curAveDou = (target * 1.0 - sum) / (arr.length - i - 1);                System.out.println(curAveDou);                if (Math.abs(curAve - curAveDou) <= 0.5) {                    return curAve;                } else {                    return (curAve + 1);                }            }        }        return arr[arr.length - 1];    }}