Leetcode之数组(二)

目录

13.single-number

14.single-number-ii

15.remove-element

16.sort-colors

17.longest-consecutive-sequence

18.spiral-matrix

19.spiral-matrix-ii

20.rotate-image

21.merge-intervals

22.insert-interval

23.container-with-most-water

24.median-of-two-sorted-arrays

25.search-a-2d-matrix

26.plus-one

27.max-points-on-a-line


13.single-number

题目:给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。说明:你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?

分析:利用异或运算的一个性质:任何一个数字异或它自己都等于0。也就是说,如果我们从头到尾依次异或数组中的每个数字,那么最终的结果刚好是那个只出现一次的数字,因为那些成对出现两次的数字全部在异或过程中抵消了。

​    public int singleNumber(int[] nums) {
        int res = nums[0];
        for(int i = 1;i < nums.length;i++)
            res ^= nums[i];
        return res;
    }

14.single-number-ii

题目:给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现了三次。找出那个只出现了一次的元素。说明:你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?

分析:见剑指offer面试题56II https://blog.csdn.net/Nibaby9/article/details/104126765

15.remove-element

题目:给定一个数组和一个值,使用就地算法将数组中所有等于这个值的元素删除,并返回新数组的长度。元素的顺序可以更改。你不用去关心大于当前数组长度的空间里面存储的值

分析:用快排思想,当遇到不等于目标值,将最后一个值往前移即可。

    public int removeElement(int[] A, int elem) {
        int low = 0,high = A.length - 1;
        while(low <= high){
            while(low <= high && A[low] != elem)
                low++;
            if(low <= high){
                A[low] = A[high];
                high--;
            }
        }
        return high + 1;
    }

16.sort-colors

问题:现在有一个包含n个物体的数组,其中物体颜色为颜色为红色、白色或蓝色,请对这个数组进行排序,让相同颜色的物体相邻,颜色的顺序为红色,白色,蓝色。我们用0,1,2分别代表颜色红,白,蓝。注意:本题要求你不能使用排序库函数。扩展:一个非常直接的解法是两步的计数排序的算法,首先:遍历一遍数组,记录0,1,2的数量,然后重写这个数组,先将0写入,再将1写入,再将2写入,你能给出一个只用一步,并且能在常数级空间复杂度解决这个问题的算法吗?

分析:设置三个变量,一个变量记录0的后一个位置,一个变量记录2前一个的位置,一个变量用来遍历当前数组。

    public void sortColors(int[] A) {
        int low = 0,index = 0,high = A.length - 1;
        while(index <= high){
           if(A[index] == 0){
               A[low] = 0;
               low++;index++;
           }
           else if(A[index] == 2){
               A[index] = A[high];
               A[high] = 2;
               high--;
           }
           else
               index++;
        }
        while(low <= high)
            A[low++] = 1;
    }

17.longest-consecutive-sequence

题目:给定一个无序的整数类型数组,求最长的连续元素序列的长度。例如:给出的数组为[100, 4, 200, 1, 3, 2],最长的连续元素序列为[1, 2, 3, 4]. 返回这个序列的长度:4。你需要给出时间复杂度在O(n)之内的算法

分析:先初始化一个HashMap,key为数组中的每个元素,value表示是否访问过;然后再遍历这个数组,看该元素是否访问过,如果没有则统计其相邻元素是否存在,每访问一个元素都将其value设置为true。

     public int longestConsecutive(int[] num) {
        if(num == null || num.length == 0)
            return 0;
        int max = 1;
        HashMap<Integer,Boolean> map = new HashMap();
        for(int i = 0;i < num.length;i++)
            map.put(num[i],false);
        for(int i = 0;i < num.length;i++){
            int count = 1;
            if(! map.get(num[i])){
                int key = num[i];
                map.put(key,true);
                while(map.containsKey(--key) && !map.get(key)){
                    count++;
                    map.put(key,true);
                }
                key = num[i];
                while(map.containsKey(++key) && !map.get(key)){
                    count++;
                    map.put(key,true);
                }
                if(count > max)
                    max = count;
            }
        }
        return max;
    }

18.spiral-matrix

题目:给定一个m x n大小的矩阵(m行,n列),按螺旋的顺序返回矩阵中的所有元素。例如,给出以下矩阵:[↵ [ 1, 2, 3 ],↵ [ 4, 5, 6 ],↵ [ 7, 8, 9 ]↵],你应该返回[1,2,3,6,9,8,7,4,5]。

分析:见剑指offer面试题29 https://blog.csdn.net/Nibaby9/article/details/104126765

19.spiral-matrix-ii

题目:给定一个整数n,将数字1到n^2n2按螺旋的顺序填入n×n的矩阵。例如:给出的n=3,你应该返回如下矩阵:[↵ [ 1, 2, 3 ],↵ [ 8, 9, 4 ],↵ [ 7, 6, 5 ]↵]

分析:同上题思路一样,分别用四个数记录开始行、结束行、开始列、结束列即可。

   public int[][] generateMatrix(int n) {
        int[][] result = new int[n][n];
        int row = 0, row_end = n - 1, col = 0, col_end = n - 1;
        int count = 1, sum = n * n;
        while (count <= sum) {
            for (int i = col; i <= col_end; i++, count++)
                result[row][i] = count;
            row++;
            for (int i = row; i <= row_end; i++, count++)
                result[i][col_end] = count;
            col_end--;
            for (int i = col_end; i >= col; i--, count++)
                result[row_end][i] = count;
            row_end--;
            for (int i = row_end; i >= row; i--, count++) 
                result[i][col] = count;
            col++;
        }
        return result;
    }

20.rotate-image

题目:给出一个用二维矩阵表示的图像,返回该图像顺时针旋转90度的结果。扩展:你能使用原地算法解决这个问题么?

分析:一个点顺时针旋转90度,就是该点关于y = x对称,再关于x轴对称。所以只要将图像做两次翻转,先沿右上-左下的对角线翻转,再沿水平中线上下翻转。注:点(i,j)沿对角线翻转的对应点为(n-1-j,n-1-i).

    public void rotate(int[][] matrix) {
        int n = matrix.length;
        for(int i = 0;i < n;i++){
            for(int j = 0;j < n - i;j++){
                int temp = matrix[i][j];
                matrix[i][j] = matrix[n-1-j][n-1-i];
                matrix[n-1-j][n-1-i] = temp;
            }
        }
        for(int i = 0;i < n / 2;i++){
            for(int j = 0;j < n;j++){
                int temp = matrix[i][j];
                matrix[i][j] = matrix[n-1-i][j];
                matrix[n-1-i][j] = temp;
            }
        }
    }

21.merge-intervals

题目:给出一组区间,请合并所有重叠的区间。例如,给出[1,3],[2,6],[8,10],[15,18],返回[1,6],[8,10],[15,18].

分析:先利用list中的比较器对区间的x值进行排序,再遍历每个区间,查看该区间与上一区间是否重叠,如果重叠则合并,并把上个区间设为null,最后再移除所有的null值即可。

    public ArrayList<Interval> merge(ArrayList<Interval> intervals) {
        Collections.sort(intervals, new Comparator<Interval>() {//intervals中按start从小到大排序
            @Override
            public int compare(Interval o1, Interval o2) {
                return o1.start - o2.start;
            }
        });
        for(int i = 1;i < intervals.size();i++){
            int x1 = intervals.get(i - 1).start;
            int y1 = intervals.get(i - 1).end;
            int x2 = intervals.get(i).start;
            int y2 = intervals.get(i).end;
            if(x2 <= y1){
                intervals.set(i,new Interval(x1,Math.max(y1,y2)));
                intervals.set(i-1,null);
            }
        }
        while (intervals.remove(null)) ;//删除list中所有的null值
        return intervals;
    }

22.insert-interval

题目:给定一组不重叠的时间区间,在时间区间中插入一个新的时间区间(如果有重叠的话就合并区间)。这些时间区间初始是根据它们的开始时间排序的。示例1:给定时间区间[1,3],[6,9],在这两个时间区间中插入时间区间[2,5],并将它与原有的时间区间合并,变成[1,5],[6,9].示例2:给定时间区间[1,2],[3,5],[6,7],[8,10],[12,16],在这些时间区间中插入时间区间[4,9],并将它与原有的时间区间合并,变成[1,2],[3,10],[12,16].这是因为时间区间[4,9]覆盖了时间区间[3,5],[6,7],[8,10].

分析:直接将时间区间加入list中,利用上题代码即可。或者将该区间插入,再依次两两合并即可,注意插入位置为第一个位置的情况。

     public ArrayList<Interval> insert(ArrayList<Interval> intervals, Interval newInterval) {
        if(intervals.size() == 0){
            intervals.add(newInterval);
            return intervals;
        }
        int i = 0;
        while(i < intervals.size() && intervals.get(i).start <= newInterval.start)
            i++;
        intervals.add(i,newInterval);
        if(i == 0)//插在第一个位置
           i = 1;
        for(;i < intervals.size();i++){
            int x1 = intervals.get(i-1).start;
            int y1 = intervals.get(i-1).end;
            int x2 = intervals.get(i).start;
            int y2 = intervals.get(i).end;
            if(x2 <= y1){
                intervals.set(i,new Interval(x1,Math.max(y1,y2)));
                intervals.set(i - 1,null);
            }
        }
        while(intervals.remove(null));
        return intervals;
    }

23.container-with-most-water

题目:给定n个非负整数a1,a2,…,an,其中每个数字表示坐标(i, ai)处的一个点。以(i,ai)和(i,0)(i=1,2,3...n)为端点画出n条直线。你可以从中选择两条线与x轴一起构成一个容器,最大的容器能装多少水?注意:你不能倾斜容器。例如:输入 [1,8,6,2,5,4,8,3,7],输出: 49

分析:从两端开始向中间逼近找全局最优,每次移动较短边(移动较长边可能会导致下一个矩形因为短边限制取不到最优)。

   public int maxArea(int[] height) {
        int max = 0;
        int left = 0,right = height.length - 1;
        while(left < right){
            int area = (right - left) * Math.min(height[left],height[right]);
            if(area > max)
                max = area;
            //每次移动最短边
            if(height[left] < height[right])
                left++;
            else
                right--;
        }
        return max;
    }

24.median-of-two-sorted-arrays

题目:有两个大小分别为m和n的有序数组A和B。请找出这两个数组的中位数。你需要给出时间复杂度在O(log (m+n))以内的算法。

分析:将原问题转变为寻找第k小的数。假设数组A和B的元素个数都大于k/2,比较A[k/2-1]和B[k/2-1]两个元素,根据不同情况递归求解即可。注意边界,开始查找索引大于数组长度以及k=1的情况。

    public double findMedianSortedArrays(int A[], int B[]) {
        int len = A.length + B.length;
        if(len % 2 == 1)
            return findKth(A,0,B,0,len / 2 + 1);
        else
            return (findKth(A,0,B,0,len / 2) + findKth(A,0,B,0,len / 2 + 1)) / 2;
    }

    private double findKth(int[] a, int as, int[] b, int bs, int k) {
        if (as >= a.length)
            return b[bs + k - 1];
        if (bs >= b.length)
            return a[as + k - 1];
        if(k == 1)
            return Math.min(a[as],b[bs]);
        int aMin = Integer.MAX_VALUE, bMin = Integer.MAX_VALUE;
        if(as + k / 2 - 1 < a.length)
            aMin = a[as + k / 2 - 1];
        if(bs + k / 2 - 1 < b.length)
            bMin = b[bs + k / 2 - 1];
        if(aMin < bMin)
            return findKth(a,as + k/2,b,bs,k - k/2);
        else
            return findKth(a,as,b,bs + k/2,k - k/2);
    }

25.search-a-2d-matrix

题目:请写出一个高效的在m*n矩阵中判断目标值是否存在的算法,矩阵具有如下特征:每一行的数字都从左到右排序,每一行的第一个数字都比上一行最后一个数字大。例如:对于下面的矩阵:[↵ [1, 3, 5, 7],↵ [10, 11, 16, 20],↵ [23, 30, 34, 50]↵],要搜索的目标值为3,返回true。

分析:见剑指offer面试题4 https://blog.csdn.net/Nibaby9/article/details/104126765

26.plus-one

题目:给出用数字数组表示的一个非负整数,请对该整数加1。

分析:递归即可。特别注意99+1这种最高位需要进位的情况。

    public int[] plusOne(int[] digits) {
        if(digits.length == 0)
            return digits;
        return plusOne(digits,digits.length - 1);
    }

    private int[] plusOne(int[] digits, int index) {
        if(index < 0){//最高位进位!!!
            int[] a = new int[digits.length + 1];
            a[0] = 1;
            for(int i = 0;i < digits.length;i++)
                a[i + 1] = digits[i];
            return a;
        }
        digits[index]++;
        if(digits[index] <= 9)
            return digits;
        digits[index] = 0;
        return plusOne(digits,index - 1);
    }

27.max-points-on-a-line

题目:对于给定的n个位于同一二维平面上的点,求最多能有多少个点位于同一直线上

分析:两个点构成一条直线,所以对于n个点可以构成n-1条直线(需考虑两个点重合的情况),只要判断有多少个点在这些直线上即可。而为了避免除数为0而出错的情况,我们用 dy * (x1-x2)== dx * (y1-y2)来判断一个点是否在一条直线上。

    public int maxPoints(int[][] points) {
        int len = points.length;
        if(len < 3)
            return len;
        //先对点进行排序,将横坐标纵坐标差值较小的点排在前面
        Arrays.sort(points, new Comparator<int[]>(){
            public int compare(int[] arr1, int[] arr2){
                return Math.abs(arr1[0] - arr1[1]) - Math.abs(arr2[0] - arr2[1]);
            }
        });
        int sum = 0;
        for(int i = 1;i < len;i++){
            int count = 0;
            int dx = points[i-1][0] - points[i][0];
            int dy = points[i-1][1] - points[i][1];
            if(dx==0 && dy==0){//重合点
                for(int j = 0;j < len;j++){
                    if(points[j][0] == points[i][0] && points[j][1] == points[i][1])
                        count++;
                }
            }
            else {
                for(int j = 0;j < len;j++){//long型防止溢出
                    long detay = points[j][1] - points[i][1];
                    long detax = points[j][0] - points[i][0];
                    if (dx * detay == dy * detax)
                        count++;
                }
            }
            sum = Math.max(count,sum);
        }
        return sum;
    }

猜你喜欢

转载自blog.csdn.net/Nibaby9/article/details/104677497