leetcode刷题笔记

算法题

1、Product of Array Except Self

题目说明:给定长度为 n 的整数数组 nums,其中 n > 1,返回输出数组 output ,其中 output[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积。

示例:

输入: [1,2,3,4]
输出: [24,12,8,6]

说明: 请不要使用除法,且在 O(n) 时间复杂度内完成此题。

进阶:你可以在常数空间复杂度内完成这个题目吗?( 出于对空间复杂度分析的目的,输出数组不被视为额外空间。) 【进阶在第二阶段优化】


解题思路:原本计算出所有数的积然后分别除掉每个数就行了,但原题要求不能用除法,那么,我们就只能使用乘法了。在只使用乘法的情况下想要时间复杂度达到O(n),则需要避免其中重复计算。

假设对于数组 nums[]={2, 3, 4, 5 }, 假设result[]为最后结果,可以得到:

只需要计算出左边A、右边B这两个三角形上每行的乘积,就可以得到result了。如下(n表示输入数组的长度,即 n=input.lenght):

A[0]=1;   A[1]=1*input[0]=A[0]*input[0];         A[2]=A[1]*input[1]        =>  A[i]=A[i-1]*input[i-1],i从小到大取值范围为[2, n),
B[n-1]=1; B[n-2]=1*input[n-1]=B[n-1]*input[n-1]; B[n-3]=B[n-2]*input[n-2]  =>  B[i]=B[i+1]*input[i+1],i从大到小取值范围为[n-2, 0]
result[0]=A[0]*B[0]; result[1]=A[1]*B[1]  =>  result[i]=A[i]*B[i]

以此类推,计算A、B就简单了,完全可以在O(n)内办到,代码实现如下(java):

public class Solution {
    public static void main(String[] args) {
        Solution solution = new Solution();
        
        int[] input = new int[] {1,2,3,4};
        int[] output = solution.productExceptSelf(input);
        
        solution.printResult(output);
    }
    private void printResult(int[] result) {
        StringBuffer sb = new StringBuffer("output[");
        for(int i=0; i<result.length; i++) {
            sb.append(result[i]);
            if(i < result.length-1) {
                sb.append(",");
            }
        }
        sb.append("]");
        System.out.println(sb.toString());
    }
    
    //算法代码写在这里
    public int[] productExceptSelf(int[] nums) {
        int[] res = new int[nums.length];
        int[] left = new int[nums.length];
        int[] right = new int[nums.length];
        
        left[0] = 1;
        for(int i=1; i<nums.length; i++) {
            left[i] = left[i-1] * nums[i-1];
        }
        
        right[nums.length-1] = 1;
        for(int i=nums.length-2; i>=0; i--) {
            right[i] = right[i+1] * nums[i+1];
        }
        
        for(int i=0; i<nums.length; i++) {
            res[i] = left[i] * right[i];
        }
        return res;
    }
}

 2、螺旋矩阵

题目说明:给定一个包含 m x n 个元素的矩阵(m 行, n 列),请按照顺时针螺旋顺序,返回矩阵中的所有元素。

示例:

输入:
[
 [ 1, 2, 3 ],
 [ 4, 5, 6 ],
 [ 7, 8, 9 ]
]
输出: [1,2,3,6,9,8,7,4,5]

输入:
[
  [1, 2, 3, 4],
  [5, 6, 7, 8],
  [9,10,11,12]
]
输出: [1,2,3,4,8,12,11,10,9,5,6,7]

解题思路:循环走回路,每次回路分为四个方向--向右、向下、向左、向上,每次朝一个方向到达边界就需要执行一些操作--【变换方向,改变该方向上的边界值】,知道遍历完矩阵中的所有元素,即要进行 m*n 次取矩阵元素值添加到返回值列表中,因此循环次数为 m*n ,并且在每次循环中判断走向

代码实现如下,时间复杂度为O(m*n):

//m行n列矩阵
    public List<Integer> spiralOrder(int[][] matrix){
        List<Integer> order = new ArrayList<Integer>();
        int m = matrix.length;
        int n = matrix[0].length;
        int len = m*n;
        //行坐标,列坐标
        int row = 0, col = 0;
        //循环:左最小leftMin++,右最大n-1--,上最小topMin++,下最大m-1--
        int leftMin = 0, topMin = 1;
        //四个方向,向右:row不变,col++;向下:row++,col不变;向左:row不变,col--;向上:row--,col不变
        int[][] dir= {
                {0,1,0,-1},//row的变化值
                {1,0,-1,0}//col的变化值
                };
        //k值改变标志着方向的变化,k%4余数:0-右,1-下,2-左,3-上
        int k = 0;
        for(int i=0; i<len; i++) {
            //改变row和col的业务逻辑
            order.add(matrix[row][col]);
            row += dir[0][k%4];
            col += dir[1][k%4];
            
            switch(k%4) {
                case 0://右行
                    //判断是否到达右边界,col=n-1时即到达右边界,此时界限缩小,需要换方向
                    if(col > n-1) {
                        col = n-1;
                        k++;
                        n--;
                        //向下一
                        row++;
                    }
                    break;
                case 1://下行
                    //判断是否到达下边界,col=n-1时即到达下边界,此时界限缩小,需要换方向
                    if(row > m-1) {
                        row = m-1;
                        k++;
                        m--;
                        //向左一
                        col--;
                    }
                    break;
                case 2://左行
                    //判断是否到达左边界,col=leftMin时即到达左边界,此时界限缩小,需要换方向
                    if(col < leftMin) {
                        col = leftMin;
                        k++;
                        leftMin++;
                        //向上一
                        row--;
                    }
                    break;
                case 3://上行
                    //判断是否到达上边界,row=topMin时即到达上边界,此时界限缩小,需要换方向
                    if(row < topMin) {
                        row = topMin;
                        k++;
                        topMin++;
                        //向右一
                        col++;
                    }
                    break;
            }
        }
        return order;
    }

 

posted @ 2019-03-30 12:32  将王相  阅读(148)  评论(0)    收藏  举报