LeetCode刷题(废弃)

这篇博客分享了作者在LeetCode上刷题的心得,涵盖了分治法、数组、字符串、动态规划、贪心算法、数学、栈、树、哈希表、链表、深度优先搜索、广度优先搜索、双指针、二分查找、堆等多个算法和数据结构。博客探讨了具体题目和解题策略,包括一些常见算法的优化和思考,适合巩固算法知识。
摘要由CSDN通过智能技术生成

重要提示:该博客不再更新!最新文章请参考LeetCode系列!

为了更好地巩固算法知识,打下扎实的计算机基础。。。好吧,实在编不下去了。。。其实是闲着没事儿做,不如动动脑,刷刷题,被虐一虐。以前零零散散也刷了一些,这次我准备按专题来刷,更有针对性一些。下面将会出现一些部分专题的刷题感悟,没事儿您就看看呗,哈哈哈!

1.Divide and Conquer

1.Majority Element

Given an array of size n, find the majority element. The majority element is the element that appears more than ⌊ n/2 ⌋ times.

You may assume that the array is non-empty and the majority element always exist in the array.
解答:

public class Solution {
    //success 1
    //sort方法,很trick,对于任何数组来说,如果存在majority element,sort后一定在length/2处。
    // public int majorityElement(int[] nums) {
   
    //     Arrays.sort(nums);
    //     int length = nums.length;
    //     return nums[length/2];
    // }
    //success 2
    //利用hashMap
    // public int majorityElement(int[] nums) {
   
    //     int length = nums.length;
    //     HashMap<Integer,Integer> map = new HashMap<>();
    //     for (int num:
    //          nums) {
   
    //         if(!map.containsKey(num)){
   
    //             map.put(num,1);
    //         }else{
   
    //             int value = map.get(num)+1;
    //             map.put(num,value);
    //         }
    //         if(map.get(num)>length/2){
   
    //                 return num;
    //             }
    //     }
    //     return -1;
    // }
    //success 3
    //该问题专用的算法:Boyer–Moore majority vote algorithm
    public int majorityElement(int[] nums) {
        int value = Integer.MAX_VALUE;
        int count = 0;
        for (int num:
             nums) {
            if(count==0){
                value = num;
                count++;
            }else if(value!=num){
                count--;
            }else{
                count++;
            }
        }
        return value;
    }
}

关于算法三,可以参考Boyer–Moore majority vote algorithm。另附:一个演示该算法的网站

2.Search a 2D Matrix II

Write an efficient algorithm that searches for a value in an m x n matrix. This matrix has the following properties:

1.Integers in each row are sorted in ascending from left to right.
2.Integers in each column are sorted in ascending from top to bottom.

从上面两条规则可以得出,一个元素的所有左上角元素一定比之小,一个元素的所有右下角元素一定比之大,其他部位(右上角和左下角)的所有元素与之关系不确定。
For example,

Consider the following matrix:

[
  [1,   4,  7, 11, 15],
  [2,   5,  8, 12, 19],
  [3,   6,  9, 16, 22],
  [10, 13, 14, 17, 24],
  [18, 21, 23, 26, 30]
]

Given target = 5, return true.
Given target = 20, return false.

我刚开始误以为对角线元素可以做分割,但之后确认是错误的,贴出错误代码:

//请注意,该代码不完整,只是为了演示我最初的思路
public boolean findMatrix(int[][] matrix,int[] start,int[] end,int target) {
            int[] middle = new int[2];
            middle[0] = (start[0]+end[0])/2;
            middle[1] = (start[1]+end[1])/2;
            int middleValue = matrix[middle[0]][middle[1]];
            if(target==middleValue){
                return true;
            }else if(target<middleValue){
            //错误思路:只考虑左上角
                return findMatrix(matrix,start,middle,target);
            }else if(target>middleValue){
            //错误思路:只考虑右下角
                return findMatrix(matrix,middle,end,target);
            }
            }

思路2:根据规则,最左上为最小,最右下为最大。跟这样的元素做比较然后通过递归调用是没有用的,因为对于不同的路分割条件是一样的。

如果取右上角元素就可以递归,因为不同的路分割条件是不一样的。比如,如果target比该元素小,那么排除该元素所在的列(因为都比target大),同理,如果比该元素小,排除该元素所在的行。这样,每次调用方法都排除一行或一列,总的时间复杂度为O(M+N)

代码如下:

public class Solution {
   
    public boolean searchMatrix(int[][] matrix, int target) {
        int M = matrix.length;
        int N = matrix[0].length;
        if(target<matrix[0][0]||target>matrix[M-1][N-1]){
            return false;
        }
        boolean result = findTarget(matrix,0,N-1,target);
        return result;
    }
    public boolean findTarget(int[][] matrix,int row,int column,int target){
        if(row>=0&&row<matrix.length&&column>=0&&column<matrix[0].length){
            int compareValue = matrix[row][column];
            if(target==compareValue){
                return true;
            }else if(target<compareValue){
                //排除列
                return findTarget(matrix,row,column-1,target);
            }else if(target>compareValue){
                //排除行
                return findTarget(matrix,row+1,column,target);
            }
        }else{
            return false;
        }
        return false;
    }
    }

上述代码解决很优美,如果想关于此题的更多解法,可参考Search in a Sorted Matrix

3.Kth Largest Element in an Array

Find the kth largest element in an unsorted array. Note that it is the kth largest element in the sorted order, not the kth distinct element.

For example,
Given [3,2,1,5,6,4] and k = 2, return 5.

代码如下:

public class Solution {
    //success 1
    //O(N lg N) running time + O(1) memory
    //直接排序,然后找出来
    // public int findKthLargest(int[] nums, int k) {
   
    //     Arrays.sort(nums);
    //     int reveredK = nums.length+1-k;
    //     return nums[reveredK-1];
    // }

    //success 2
    //O(N lg K) running time + O(K) memory
    //维护一个k size的优先队列
    public int findKthLargest(int[] nums, int k) {
    //对于Integer来说,优先队列默认顺序是数值小的在队列头
    final PriorityQueue<Integer> pq = new PriorityQueue<>();
    for(int val : nums) {
        //添加进队列,添加后会自动排序
        pq.offer(val);
        if(pq.size() > k) {
            //弹出队列头元素
            pq.poll();
        }
    }
    //取得队列头元素值,但不弹出
    return pq.peek();
}
}

4.Maximum Subarray

Find the contiguous subarray within an array (containing at least one number) which has the largest sum.

For example, given the array [-2,1,-3,4,-1,2,1,-5,4],
the contiguous subarray [4,-1,2,1] has the largest sum = 6.

第一种方法很简单,直接写:

public class Solution {
   
    //success 1
    //直接写,很简单
    public int maxSubArray(int[] nums) {
        int count=0,largest=Integer.MIN_VALUE;
        for (int i = 0; i < nums.length; i++) {
            count+=nums[i];
            if(count>largest){
                largest=count;
            }
            if(count<0){
                count=0;
            }
        }
        return largest;
    }
    }

我自己写的算法居然还跟著名的算法Kadane’s Algorithm一样!哈哈哈!它应该是针对此类问题的比较好的解法。

第二种方法,我想用分治法实现,但是出问题了,代码如下:

public class Solution {
    public int maxSubArray(int[] nums) {
        if(nums.length==1){
            return nums[0];
        }
        if(nums.length==2){
            return Math.max(nums[0]+nums[1],Math.max(nums[0],nums[1]));
        }
        int[] result = findMaxArray(nums,0,nums.length-1);
        return result[2];
    }
    public int[] findMaxArray(int[] nums,int left,int right){
        //return maxsum's low,high and the sum
        System.out.println(left+" "+right);
        if(right==left){
            int[] result = {left,right,nums[left]};
            return result;
        }
        //注意:此种写法容易引起溢出
        //int middle = (left+right)/2;
        //正确写法
        int middle = left+(right-left)/2;
        int[] leftResult = findMaxArray(nums,left,middle);
        int[] rightResult = findMaxArray(nums,middle+1,right);
        int leftLargest = leftResult[2];
        int rightLargest = rightResult[2];
        int leftHigh = leftResult[1];
        int rightLow = rightResult[0];
        int intervalSum=0;
        for (int i = leftHigh+1; i < rightLow; i++) {
            intervalSum+=nums[i];
        }
        int middleLargest = leftLargest+rightLargest+intervalSum;
        System.out.println("left: "+leftLargest+" right: "+rightLargest+" middle: "+middleLargest);
        if(leftLargest >= rightLargest && leftLargest >= middleLargest){
  // left part is max
            System.out.println("left");
            return leftResult;
        }
        if(rightLargest >= leftLargest && rightLargest >= middleLargest){
  // right part is max
            System.out.println("right");
            return rightResult;
        }
        System.out.println("middle");
        int[] result = {leftResult[0],rightResult[1],middleLargest};
        return result;
    }
    }

通过打log,输出如下:

0 8
0 4
0 2
0 1
0 0
1 1
left: -2 right: 1 middle: -1
right
2 2
left: 1 right: -3 middle: -2
left
3 4
3 3
4 4
left: 4 right: -1 middle: 3
left
left: 1 right: 4 middle: 2
right
5 8
5 6
5 5
6 6
left: 2 right: 1 middle: 3
middle
7 8
7 7
8 8
left: -5 right: 4 middle: -1
right
left: 3 right: 4 middle: 2
right
left: 4 right: 4 middle: 5
middle

通过log,分析得出错误原因:在定义middle时并不是包含中间元素的最大和子数组。log中发现对于leftLargest=4,rightLargest=4时,程序发现[4,-1,2,1,-5,4]和为5,比leftLargest和rightLargest都大,所以输出最大和子数组为5。但是,我们可以通过[4,-1,2,1]发现最大和为6。

修改定义middle的策略,得出正确答案:

public class Solution {
    public int maxSubArray(int[] nums) {
        if(nums.length==1){
            return nums[0];
        }
        if(nums.length==2){
            return Math.max(nums[0]+nums[1],Math.max(nums[0],nums[1]));
        }
        int[] result = findMaxArray(nums,0,nums.length-1);
        return result[2];
    }
public int[] findMaxArray(int[] nums,int left,int right){
        //return maxsum's low,high and the sum
        System.out.println(left+" "+right);
        if(right==left){
            int[] result = {left,right,nums[left]};
            return result;
        }
        //注意:此种写法容易引起溢出
        //int middle = (left+right)/2;
        //正确写法
        int middle = left+(right-left)/2;
        int[] leftResult = findMaxArray(nums,left,middle);
        int[] rightResult = findMaxArray(nums,middle+1,right);
        int leftLargest = leftResult[2];
        int rightLargest = rightResult[2];
        int leftSum=Integer.MIN_VALUE,rightSum=Integer.MIN_VALUE,leftSumTmp=0,rightSumTmp=0,middleLeft=0,middleRight=0;
        for (int i = middle; i >=left; i--) {
            leftSumTmp+=nums[i];
            if(leftSumTmp>leftSum){
                leftSum = leftSumTmp;
                middleLeft=i;
            }
        }
        for (int i = middle+1; i <=right; i++) {
            rightSumTmp+=nums[i];
            if(rightSumTmp>rightSum){
                rightSum = rightSumTmp;
                middleRight=i;
            }
        }
        int middleLargest = leftSum+rightSum;
        System.out.println("left: "+leftLargest+" right: "+rightLargest+" middle: "+middleLargest);
        if(leftLargest >= rightLargest && leftLargest >= middleLargest){
  // left part is max
            System.out.println("left");
            return leftResult;
        }
        if(rightLargest >= leftLargest && rightLargest >= middleLargest){
  // right part is max
            System.out.println("right");
            return rightResult;
        }
        System.out.println("middle");
        int[] result = {middleLeft,middleRight,middleLargest};
        return result;
    }
    }

通过log发现,程序正常运转:

0 8
0 4
0 2
0 1
0 0
1 1
left: -2 right: 1 middle: -1
right
2 2
left: 1 right: -3 middle: -2
left
3 4
3 3
4 4
left: 4 right: -1 middle: 3
left
left: 1 right: 4 middle: 2
right
5 8
5 6
5 5
6 6
left: 2 right: 1 middle: 3
middle
7 8
7 7
8 8
left: -5 right: 4 middle: -1
right
left: 3 right: 4 middle: 2
right
left: 4 right: 4 middle: 6
middle
//最大子数组start index
3
//最大子数组end index
6
//最大子数组sum
6

5.Count of Smaller Numbers After Self

You are given an integer array nums and you have to return a new counts array. The counts array has the property where counts[i] is the number of smaller elements to the right of nums[i].

Example:

Given nums = [5, 2, 6, 1]
Return the array [2, 1, 1, 0].

第一种思路比较简单,就是无脑对比,贴上源码:

public class Solution {
    //fail 1,Time Limit Exceeded
    //思想很朴素,就是无脑对比
    public List<Integer> countSmaller(int[] nums) {
        if(nums.length==0){
            return new ArrayList<>();
        }
        Integer[] smallerArray = new Integer[nums.length];
        smallerArray[smallerArray.length-1] = 0;
        for (int i = nums.length-2; i >=0; i--) {
            int count=0;
            for (int j = i; j < nums.length; j++) {
                if(nums[i]>nums[j]){
                    count++;
                }
                if(j==nums.length-1){
                    smallerArray[i]=count;
                }
            }
        }
        List<Integer> list = new ArrayList<>();
        list = Arrays.asList(smallerArray);
        return list;
    }
}

此方法的时间效率不高,在submit时会出现TimeOut。得想出更高效率的算法啊。有大神在Discuss中提到一个思路:

The smaller numbers on the right of a number are exactly those that jump from its right to its left during a stable sort. So I do mergesort with added tracking of those right-to-left jumps.

因此我可以用merge sort的思想实现试试。

首先温习一下merge sort:
Merge Sort

贴出源码:

public class Solution {
   

    //success 2
    //运用merge sort追加记录的方式实现
    public List<Integer> countSmaller(int[] nums) {
        Integer[] smaller = new Integer[nums.length];
        Arrays.fill(smaller,0);
        MapNums[] mapNums= new MapNums[nums.length];
        for (int i = 0; i < nums.length; i++) {
            mapNums[i] = new MapNums(i,nums[i]);
        }
        sort(mapNums, 0, mapNums.length-1,smaller);
        List<Integer> list = new ArrayList<>();
        list = Arrays.asList(smaller);
        return list;
    }

    void merge(MapNums arr[], int l, int m, int r,Integer[] smaller)
    {
        // Find sizes of two subarrays to be merged
        int n1 = m - l + 1;
        int n2 = r - m;

        /* Create temp arrays */
        MapNums L[] = new MapNums [n1];
        MapNums R[] = new MapNums [n2];

        /*Copy data to temp arrays*/
        for (int i=0; i<n1; ++i)
            L[i] = arr[l + i];
        for (int j=0; j<n2; ++j)
            R[j] = arr[m + 1+ j];


        /* Merge the temp arrays */

        // Initial indexes of first and second subarrays
        int i = 0, j = 0;

        // Initial index of merged subarry array
        int k = l;
        while (i < n1 && j < n2)
        {
            if (L[i].number <= R[j].number)
            {
                arr[k] = L[i];
                //本算法精髓
                smaller[L[i].index]+=j;
                i++;
            }
            else
            {
                arr[k] = R[j];
                j++;
            }
            k++;
        }

        /* Copy remaining elements of L[] if any */
        while (i < n1)
        {
            arr[k] = L[i];
            //本算法精髓
            smaller[L[i].index]+=j;
            i++;
            k++;
        }

        /* Copy remaining elements of L[] if any */
        while (j < n2)
        {
            arr[k] = R[j];
            j++;
            k++;
        }
    }

    // Main function that sorts arr[l..r] using
    // merge()
    void sort(MapNums arr[], int l, int r,Integer[] smaller)
    {
        if (l < r)
        {
            // Find the middle point
            //注意:此种写法容易引起溢出
            //int m = (l+r)/2;
            //正确写法
            int m = l+(r-l)/2;
            // Sort first and second halves
            sort(arr, l, m,smaller);
            sort(arr , m+1, r,smaller);

            // Merge the sorted halves
            merge(arr, l, m, r,smaller);
        }
    }

//内部类
//类MapNums主要是记录每个元素的index和number,
//因为运用merge sort排序后,如果不记录index(在原始数组中的位置)的话,就没有办法向smaller数组中写入正确信息。
class MapNums{
   
    int number;
    int index;
    public MapNums(int index,int number){
        this.index = index;
        this.number = number;
    }
}

}

2.Array

1.Contains Duplicate

Given an array of integers, find if the array contains any duplicates. Your function should return true if any value appears at least twice in the array, and it should return false if every element is distinct.

运用merge sort的实现:

public class Solution {
   

    //success 1
    //运用merge sort的思想,如果在sort或merge中有相同的情况,那么返回true,否则为false。时间复杂度为O(NlogN)
    public boolean containsDuplicate(int[] nums) {
        return sort(nums,0,nums.length-1);
    }

    /* Java program for Merge Sort */
        // Merges two subarrays of arr[].
        // First subarray is arr[l..m]
        // Second subarray is arr[m+1..r]
        boolean merge(int arr[], int l, int m, int r)
        {
            // Find sizes of two subarrays to be merged
            int n1 = m - l + 1;
            int n2 = r - m;

        /* Create temp arrays */
            int L[] = new int [n1];
            int R[] = new int [n2];

        /*Copy data to temp arrays*/
            for (int i=0; i<n1; ++i)
                L[i] = arr[l + i];
            for (int j=0; j<n2; ++j)
                R[j] = arr[m + 1+ j];


        /* Merge the temp arrays */

            // Initial indexes of first and second subarrays
            int i = 0, j = 0;

            // Initial index of merged subarry array
            int k = l;
            while (i < n1 && j < n2)
            {
                if (L[i] < R[j])
                {
                    arr[k] = L[i];
                    i++;
                }
                else if(L[i] > R[j])
                {
                    arr[k] = R[j];
                    j++;
                }else{
                    return true;
                }
                k++;
            }

        /* Copy remaining elements of L[] if any */
            while (i < n1)
            {
                arr[k] = L[i];
                i++;
                k++;
            }

        /* Copy remaining elements of L[] if any */
            while (j < n2)
            {
                arr[k] = R[j];
                j++;
                k++;
            }
            return false;
        }

        // Main function that sorts arr[l..r] using
        // merge()
        boolean sort(int arr[], int l, int r)
        {
            if (l < r)
            {
                // Find the middle point
                //注意:此种写法容易引起溢出
                //int m = (l+r)/2;
                //正确写法
                int m = l+(r-l)/2;
                // Sort first and second halves
                boolean left = sort(arr, l, m);
                boolean right = sort(arr , m+1, r);

                // Merge the sorted halves
                boolean merge =  merge(arr, l, m, r);
                if(left||right||merge){
                    return true;
                }
            }
            return false;
        }
}

此外,还有其他的一些方法,如果追求小的时间复杂度,可以用hashTable来实现。参考:

其他解法

2.Median of Two Sorted Arrays

寻找两个数组连接起来的中位数。

There are two sorted arrays nums1 and nums2 of size m and n respectively.

Find the median of the two sorted arrays. The overall run time complexity should be O(log (m+n)).

Example 1:
nums1 = [1, 3]
nums2 = [2]

The median is 2.0
Example 2:
nums1 = [1, 2]
nums2 = [3, 4]

The median is (2 + 3)/2 = 2.5

我并没有想出实现的方式,参考Discuss中大神的思路。自己动手实现一下:

public class Solution {
    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
    int m = nums1.length;
    int n = nums2.length;

    if (m > n) {
        return findMedianSortedArrays(nums2, nums1);
    }

    int i = 0, j = 0, imin = 0, imax = m, half = (m + n + 1) / 2;
    double maxLeft = 0, minRight = 0;
    while(imin <= imax){
        i = (imin + imax) / 2;
        j = half - i;
        if(j > 0 && i < m && nums2[j - 1] > nums1[i]){
            imin = i + 1;
        }else if(i > 0 && j < n && nums1[i - 1] > nums2[j]){
            imax = i - 1;
        }else{
            if(i == 0){
                maxLeft = (double)nums2[j - 1];
            }else if(j == 0){
                maxLeft = (double)nums1[i - 1];
            }else{
                maxLeft = (double)Math.max(nums1[i - 1], nums2[j - 1]);
            }
            break;
        }
    }
    if((m + n) % 2 == 1){
        return maxLeft;
    }
    if(i == m){
        minRight = (double)nums2[j];
    }else if(j == n){
        minRight = (double)nums1[i];
    }else{
        minRight = (double)Math.min(nums1[i], nums2[j]);
    }

    return (double)(maxLeft + minRight) / 2;
}
}

3.Find Peak Element

A peak element is an element that is greater than its neighbors.

Given an input array where num[i] ≠ num[i+1], find a peak element and return its index.

The array may contain multiple peaks, in that case return the index to any one of the peaks is fine.

You may imagine that num[-1] = num[n] = -∞.

For example, in array [1, 2, 3, 1], 3 is a peak element and your function should return the index number 2.

代码如下:

public class Solution {

    //success 1
    // public int findPeakElement(int[] nums) {
   
    //     if(nums.length==1){
   
    //         return 0;
    //     }
    //     for (int i = 0; i < nums.length; i++) {
   
    //         if (i == 0) {
   
    //             if (nums[i] > nums[i + 1]) {
   
    //                 return 0;
    //             }
    //         } else if (i == nums.length - 1) {
   
    //             if (nums[i] > nums[i - 1]) {
   
    //                 return nums.length - 1;
    //             }
    //         } else {
   
    //             if (nums[i] > nums[i - 1] && nums[i] > nums[i + 1]) {
   
    //                 return i;
    //             }
    //         }

    //     }
    //     return 0;
    // }

    //success 2
    //简化1
    public int findPeakElement(int[] nums) {
        for (int i = 1; i < nums.length; i++) {
            if(nums[i-1]>nums[i]){
                return i-1;
            }
        }
        return nums.length-1;
    }
}

除了上面两种简单的方法,还有O(logN)的方法:

This problem is similar to Local Minimum. And according to the given condition, num[i] != num[i+1], there must exist a O(logN) solution. So we use binary search for this problem.

1.If num[i-1] < num[i] > num[i+1], then num[i] is peak
2.If num[i-1] < num[i] < num[i+1], then num[i+1…n-1] must contains a peak
3.If num[i-1] > num[i] > num[i+1], then num[0…i-1] must contains a peak
4.If num[i-1] > num[i] < num[i+1], then both sides have peak

方法三代码:

public class Solution {
    //success 3
    //运用binary search
    public int findPeakElement(int[] nums) {
        return findPeak(nums,0,nums.length-1);
    }

    public int findPeak(int[] num,int start,int end){
        if(start == end){
        return start;
    }else if(start+1 == end){
        if(num[start] > num[end]) return start;
        return end;
    }else{
        //注意:此种写法容易引起溢出
        //int m = (start+end)/2;
        //正确写法
        int m = start+(end-start)/2;
        //condition 1
        if(num[m] > num[m-1] && num[m] > num[m+1]){

            return m;
        //condition 3
        }else if(num[m-1] > num[m] && num[m] > num[m+1]){

            return findPeak(num,start,m-1);
        //condition 2 and conditon 4
        }else{

            return findPeak(num,m+1,end);

        }
    }

}
}

4.Find Minimum in Rotated Sorted Array

Suppose a sorted array is rotated at some pivot unknown to you beforehand.

(i.e., 0 1 2 4 5 6 7 might become 4 5 6 7 0 1 2).

Find the minimum element.

You may assume no duplicate exists in the array.

运用binary search,参考

public class Solution {
    public int findMin(int[] nums) {
        if (nums==null || nums.length==0) { return Integer.MIN_VALUE; } 
        int left = 0, right = nums.length-1;
        //保证比较数组中至少有三个元素
        while (left < right-1) {  // while (left < right-1) is a useful technique
            int mid = left + (right-left)/2;
            if (nums[mid] > nums[right]) { left = mid; }
            else { right = mid; }
        }
        if (nums[left] > nums[right]) { return nums[right]; }
        return nums[left];
    }
}

5.Find Minimum in Rotated Sorted Array II

4题上的变种(考虑有重复的元素):

Follow up for “Find Minimum in Rotated Sorted Array”:
What if duplicates are allowed?

Would this affect the run-time complexity? How and why?

public class Solution {
    public int findMin(int[] nums) {
        if (nums==null || nums.length==0) { return Integer.MIN_VALUE; } 
        int left = 0, right = nums.length-1;
        //保证比较数组中至少有三个元素
        while (left < right-1) {  // while (left < right-1) is a useful technique
            int mid = left + (right-left)/2;
            if (nums[mid] > nums[right]) { left = mid; }
            else if(nums[mid] < nums[right]) { right = mid; }
            //相等情况,不能确定在左还是右,只能减少一点边界
            else{
                right-=1;
            }
        }
        if (nums[left] > nums[right]) { return nums[right]; }
        return nums[left];
    }
}

注意:Java曾经的一个系统级的binary search bug,可以google “binary search bug”,这个bug是,当使用int mid = (left + right)/2;时,如果当left和right都很大时,left+right将发生overflow,进而产生负数,Java在2006年已经在系统级别binary search上进行了修复。但是我们自己手写代码时,如果不注意这个bug,在left和right都很大时,就会产生错误。所以我推荐使用int mid = left + (right-left)/2;,当然最精确的方法是看看Java源码中的实现,然后照着改写之。
相关文章参考:
google blog
java bug

3.String

1.Implement strStr()

Returns the index of the first occurrence of needle in haystack, or -1 if needle is not part of haystack.

思路一:直接两个指针,暴力法

public class Solution {
    //success 1
    public int strStr(String haystack, String needle) {
        //haystack长度必须大
        if(haystack.length()<needle.length()){
            return -1;
        }
        if(needle.isEmpty()){
            return 0;
        }
        for (int i = 0; i < haystack.length(); i++) {
            for(int j=0;j<needle.length();j++){
                //保证charAt(i+j)不越界
                if(i+j>=haystack.length()){
                    return -1;
                }
                if(haystack.charAt(i+j)==needle.charAt(j)){
                    if(j==needle.length()-1){
                        return i;
                    }
                    continue;
                }else{
                    break;
                }
            }
        }
        return -1;
    }

    //success 2
    //方法1的简洁版
    // public int strStr(String haystack, String needle) {
   
    //     for (int i = 0; ; i++) {
   
    //         for (int j = 0; ; j++) {
   
    //             if (j == needle.length()) return i;
    //             if (i + j == haystack.length()) return -1;
    //             if (needle.charAt(j) != haystack.charAt(i + j)) break;
    //         }
    //     }
    // }

}

思路二:可以用KMP子字符串比对算法。

下面我们先来复习一下KMP算法,参考(KMP) Pattern Matching(Substring search)实现之,使上面暴力算法的时间复杂度从O(M×N)降至O(M+N),主要思路是借助了一个辅助数组,避免了每次比对不成功时都从pattern数组最起始位置重新比较:

//success 3
//kmp的实现,参考https://www.youtube.com/watch?v=GTJr8OvyEVQ
public class Solution {
    public int strStr(String haystack, String needle) {
        char[] haystackArray = haystack.toCharArray();
        char[] needleArray = needle.toCharArray();
        //haystack长度必须大
        if (haystack.length() < needle.length()) {
            return -1;
        }
        if (needle.isEmpty()) {
            return 0;
        }
        Integer[] assistArray = patternPrehandle(needle);
        int m = haystack.length();
        int i=0,j=0;
        while(i<m){
            if(haystackArray[i]==needleArray[j]){
                i++;
                j++;
                if(j==needle.length()){
                    return i-needle.length();
                }
            }else if(j!=0){
                j = assistArray[j-1];
            }else{
                i++;
            }
        }
        return -1;
    }

    Integer[] patternPrehandle(String pattern1){
        char[] pattern = pattern1.toCharArray();
        Integer[] result = new Integer[pattern.length];
        int i=0,j=1;
        result[0] = 0;
        if(pattern.length==1){
            return result;
        }
        while((i>=0)&&(i<j)&&(j<pattern.length)){
            if(pattern[i]==(pattern[j])){
                result[j]=i+1;
                i++;
                j++;
            }else if(i!=0){
                i = result[i-1];
            }else{
                result[j]=0;
                j++;
            }
        }
        return result;
    }
}

2.Add Binary

Given two binary strings, return their sum (also a binary string).

For example,
a = “11”
b = “1”
Return “100”.

就是简单的实现二进制的加法:

public class Solution {
   
    public String addBinary(String a, String b) {
        int i=a.length()-1,j=b.length()-1;
        //进位和加和
        int carry=0,sum=0;
        StringBuilder sb = new StringBuilder("");
        while(i>=0||j>=0){
            sum=carry;//进位
            if(i>=0){
                int add1 = a.charAt(i)-'0';
                sum+=add1;
                i--;
            }
            if(j>=0){
                int add2 = b.charAt(j)-'0';
                sum+=add2;
                j--;
            }
            sb.append(String.valueOf(sum%2));
            carry=sum/2;
        }
        if(carry!=0){
            sb.append(String.valueOf(carry));
        }
        return sb.reverse().toString();
    }
}

当然,如果想要更简单一点,可以用Java自带的BigInteger实现。

3.Simplify Path

Given an absolute path for a file (Unix-style), simplify it.

For example,
path = “/home/”, => “/home”
path = “/a/./b/../../c/”, => “/c”

Corner Cases:
Did you consider the case where path = “/../”?
In this case, you should return “/”.
Another corner case is the path might contain multiple slashes ‘/’ together, such as “/home//foo/”.
In this case, you should ignore redundant slashes and return “/home/foo”.

两种方式实现,第二种更简洁明了一点:

public class Solution {
    //success 1
    //直接利用string实现
    public String simplifyPath(String path) {
        //化简成标准型
        String stardardPath="";
        String pathTmp = path.replace("/./","/");
         //循环,直到所有替换完成
        while(pathTmp.contains("/./")){
            pathTmp = pathTmp.replace(
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值