zoukankan      html  css  js  c++  java
  • Leetcode Tags(2)Array

      一、448. Find All Numbers Disappeared in an Array

    给定一个范围在  1 ≤ a[i] ≤ n ( n = 数组大小 ) 的 整型数组,数组中的元素一些出现了两次,另一些只出现一次。
    找到所有在 [1, n] 范围之间没有出现在数组中的数字。
    您能在不使用额外空间且时间复杂度为O(n)的情况下完成这个任务吗? 你可以假定返回的数组不算在额外空间内。
    输入:[4,3,2,7,8,2,3,1]
    输出:[5,6]

      1.算法思路(本题关键点:注意数组下标的范围和要求的数之间有什么联系。

      既然要遍历[1,n]中的数,由于数组中的长度已经保证了为n,因此数组的下标加上1就正好满足从1到n,因此,要对下标做文章。

      2.代码实现

      将[4,3,2,7,8,2,3,1]变成[-4,-3,-2,-7,8,2,-3,-1]然后遍历到8和2这两个正数时,就将数组下标加上1就是要求的结果了。

        public List<Integer> findDisappearedNumbers(int[] nums) {
            List<Integer> list = new ArrayList<>();
            for (int i = 0; i < nums.length; i++) {
                int val = Math.abs(nums[i]) - 1;
                if (nums[val] > 0) nums[val] = -nums[val];// 如果不进行判断,那么2和3就会反转两次,还是变成2和3,最后结果为[2,3,5,6]
            }
            for (int i = 0; i < nums.length; i++) {
                if (nums[i] > 0) list.add(i+1);
            }
            return list;
        }

      

      二、283. Move Zeroes

    Input: [0,1,0,3,12]
    Output: [1,3,12,0,0]

      1.算法思路:双指针,前一个指针指的是数组的索引,后一个指针指的是非零元素的索引

      2.代码实现

      (1)最普通的思路最清晰的双指针

        public void moveZeroes(int[] nums) {
            int prev = 0;
            int curr = 0;
            while (curr < nums.length) {
                if (nums[prev] == 0 && nums[curr] != 0) {
                    nums[prev] = nums[curr];
                    nums[curr] = 0;
                    prev++;
                    curr++;
                } else if (nums[prev] != 0 && nums[curr] == 0) {
                    prev++;
                    curr++;
                } else if (nums[prev] != 0 && nums[curr] != 0) {
                    prev++;
                    curr++;
                } else {
                    curr++;
                }
            }
        }
    Low Code

      (2)高级的双指针写法1,(关键点:nums[lastNonZeroFoundAt++]的写法)同样使用指针lastNonZeroFoundAt和指针i。

    void moveZeroes(vector<int>& nums) {
        int lastNonZeroFoundAt = 0;
        for (int i = 0; i < nums.size(); i++) {
            if (nums[i] != 0) nums[lastNonZeroFoundAt++] = nums[i];    
        }
        for (int i = lastNonZeroFoundAt; i < nums.size(); i++) nums[i] = 0;
    }

      (3)高级的双指针写法2

    void moveZeroes(vector<int>& nums) {
        for (int lastNonZeroFoundAt = 0, cur = 0; cur < nums.size(); cur++) {
            if (nums[cur] != 0) swap(nums[lastNonZeroFoundAt++], nums[cur]);
        }
    }

      三、(二维数组--九宫格问题)661. 图片平滑器

    输入:
    [[1,1,1],
     [1,0,1],
     [1,1,1]]
    输出:
    [[0, 0, 0],
     [0, 0, 0],
     [0, 0, 0]]
    解释:
    对于点 (0,0), (0,2), (2,0), (2,2): 平均(3/4) = 平均(0.75) = 0
    对于点 (0,1), (1,0), (1,2), (2,1): 平均(5/6) = 平均(0.83333333) = 0
    对于点 (1,1): 平均(8/9) = 平均(0.88888889) = 0

      1.算法思路

      之前的思路是为了防止计算的时候数周围的数没有九个,因此建立一个比原始矩阵大一圈的矩阵,然后将原来的矩阵复制到大矩阵的中间。也就是在原矩阵四周圈上一圈0;

      但是有可以不用新建矩阵的方法。(关键点:在做加法之前先判断索引是否有效,如果有效才进行加法计算)

      2.代码实现

        public int[][] imageSmoother(int[][] M) {
            int[][] res = new int[M.length][M[0].length];
            for (int i = 0; i < M.length; i++) {
                for (int j = 0; j < M[0].length; j++) {
                    int count = 0;
                    for (int x = i - 1; x <= i + 1; x++) {
                        for (int y = j - 1; y <= j + 1; y++) {
                            if (0 <= x && x < M.length && 0 <= y && y < M[0].length) {
                                res[i][j] += M[x][y];
                                count++;
                            }
                        }
                    }
                    res[i][j] /= count;
                }
            }
            return res;
        }

      四、(双指针问题,单个指针for循环)830. Positions of Large Groups

    Input: "abcdddeeeeaabbbcd"
    Output: [[3,5],[6,9],[12,14]]

      1.解法思路

      使用prev指针指向子字符串的起始位置,使用curr指向子字符串的终止位置,如果curr和prev的距离相差3就添加到列表中。

      2.代码实现(关键点:prev待定,curr指针for循环,如果当前字符和下一字符相等就什么也不做,for循环里面curr会自动加1向后移动

        public List<List<Integer>> largeGroupPositions(String S) {
            int prev = 0;
            List<List<Integer>> result = new ArrayList<>();
            for (int curr = 0; curr < S.length(); curr++) {
                if (curr == S.length() - 1 || S.charAt(curr) != S.charAt(curr+1)) {
                    if (curr-prev+1 >= 3) {
                        result.add(Arrays.asList(new Integer[] {prev, curr}));
                    }
                    prev = curr + 1;
                }
            }
            return result;
        }

      五、628. Maximum Product of Three Numbers

    Input: [1,2,3,4]
    Output: 24

      1.解法思路

      (1)常规算法,排序,由于可能存在负数的原因,而两个负数乘起来就是负数,例如{-4,-3,-2,-1,60},因此需要比较排序后的Math.max(nums[nums.length-1] * nums[nums.length-2] * nums[nums.length-3], nums[0] * nums[1] * nums[nums.length-1]);

      时间复杂度O(nlog(n)),空间复杂度O(log(n)

      (2)更快的算法,按照自己的规则手动进行排序,时间复杂度O(n),空间复杂度O(1)

        public int maximumProduct(int[] nums) {
            int min1 = Integer.MAX_VALUE, min2 = Integer.MAX_VALUE;
            int max1 = Integer.MIN_VALUE, max2 = Integer.MIN_VALUE, max3 = Integer.MIN_VALUE;
            for (int n: nums) {
                if (n <= min1) {
                    min2 = min1;
                    min1 = n;
                } else if (n <= min2) {     // n lies between min1 and min2
                    min2 = n;
                }
                if (n >= max1) {            // n is greater than max1, max2 and max3
                    max3 = max2;
                    max2 = max1;
                    max1 = n;
                } else if (n >= max2) {     // n lies betweeen max1 and max2
                    max3 = max2;
                    max2 = n;
                } else if (n >= max3) {     // n lies betwen max2 and max3
                    max3 = n;
                }
            }
            return Math.max(min1 * min2 * max1, max1 * max2 * max3);
        }

      六、(数组插入问题)(三指针问题)88. Merge Sorted Array

    Input:
    nums1 = [1,2,3,0,0,0], m = 3
    nums2 = [2,5,6],       n = 3
    
    Output: [1,2,2,3,5,6]

      1.解题思路

      由于数组插入数据的困难性,再要求将nums中的数插入到nums1的合适位置中时,可以从后往前比较,将最大的数放在nums1的最末位,一次比较。

      2.解题代码(注意点:如果nums2中的数全都先于nums1插入完成,那么nums1中无序改变了;如果nums1中的数全部都移向了nums1的后面,那么nums1前面的数将由nums2中的数依次填充。

        public void merge(int[] nums1, int m, int[] nums2, int n) {
            int i = m - 1;
            int j = n - 1;
            int k = m + n - 1;
            while (i >= 0 && j >= 0) {
                if (nums1[i] > nums2[j]) nums1[k--] = nums1[i--];
                else nums1[k--] = nums2[j--];
            }
            while (j >= 0) nums1[k--] = nums2[j--];
        }

      七、(放花问题)605. Can Place Flowers

    假设你有一个很长的花坛,一部分地块种植了花,另一部分却没有。可是,花卉不能种植在相邻的地块上,它们会争夺水源,两者都会死去。
    输入: flowerbed = [1,0,0,0,1], n = 1
    输出: True
    输入: flowerbed = [1,0,0,0,1], n = 2
    输出: False

      1.解题思路(关键点:找出位置之后,直接种上花,就不用再烦恼连续的0能种多少花的问题。)

      和前面的二维数组的边界问题一样,可以在if判断语句上面添加对索引的限制。

      遍历一次,如果存在值为0且左右都为0,那么count加1并且将该位置设为1,即种上花。

      2.代码实现(关键点:解决第一个位置和最后一个位置的问题,这种关系表达式的表达技巧

        public boolean canPlaceFlowers(int[] flowerbed, int n) {
            int count = 0, i = 0;
            while (i < flowerbed.length) {
                if (flowerbed[i] == 0 &&
                   (i == 0 || flowerbed[i-1] == 0) &&
                   (i == flowerbed.length-1 || flowerbed[i+1] == 0)) {
                    count++;
                    flowerbed[i] = 1;
                }
                i++;
            }
            return count <= n;
        }

      七点五、(坐座位问题)849. Maximize Distance to Closest Person

    输入:[1,0,0,0,1,0,1]
    输出:2
    解释:如果亚历克斯坐在第二个空位(seats[2])上,他到离他最近的人的距离为 2 。果亚历克斯坐在其它任何一个空位上,他到离他最近的人的距离为 1 。
    因此,他到离他最近的人的最大距离是 2 。 

      1.思路:和上面的养花问题一样,无非就是寻找距离1最远距离的位置,同样存在边界问题。

      2.解法

        public int maxDistToClosest(int[] seats) {
            int N = seats.length;
            int prev = -1, future = 0;
            int ans = 0;
    
            for (int i = 0; i < N; ++i) {
                if (seats[i] == 1) {
                    prev = i;
                } else {
                    while (future < N && seats[future] == 0 || future < i)
                        future++;
    
                    int left = prev == -1 ? N : i - prev;
                    int right = future == N ? N : future - i;
                    ans = Math.max(ans, Math.min(left, right));
                }
            }
    
            return ans;
        }
    双指针解法
        public int maxDistToClosest(int[] seats) {
            int N = seats.length;
            int K = 0; //current longest group of empty seats
            int ans = 0;
    
            for (int i = 0; i < N; ++i) {
                if (seats[i] == 1) {
                    K = 0;
                } else {
                    K++;
                    ans = Math.max(ans, (K + 1) / 2);
                }
            }
    
            for (int i = 0; i < N; ++i)  if (seats[i] == 1) {
                ans = Math.max(ans, i);
                break;
            }
    
            for (int i = N-1; i >= 0; --i)  if (seats[i] == 1) {
                ans = Math.max(ans, N - 1 - i);
                break;
            }
    
            return ans;
        }
    按0分组解法

      

      八、(最短无序连续子数组)581. Shortest Unsorted Continuous Subarray(TODO)

    输入: [2, 6, 4, 8, 10, 9, 15]
    输出: 5
    解释: 你只需要对 [6, 4, 8, 10, 9] 进行升序排序,那么整个表都会变为升序排序。

      1.思路:

      九、(int和Integer的问题)414. Third Maximum Number

    Input: [3, 2, 1]
    Output: 1
    Explanation: The third maximum is 1.
    
    Input: [1, 2]
    Output: 2
    Explanation: The third maximum does not exist, so the maximum (2) is returned instead.
    
    Input: [2, 2, 3, 1]
    Output: 1
    Explanation: Note that the third maximum here means the third maximum distinct number.
    Both numbers with value 2 are both considered as second maximum.

      1.解题思路:上面的有一题也是按照自己的顺序对数组进行一次遍历,然后排序找出了5个数。这里也可以用同样的原理:

      2.有问题的代码,在定义了int类型的Integer.MIN_VALUE后,如果输入是{2,1,Integer.MIN_VALUE}那么根据return语句可以知道返回结果并不是Integer.MIN_VALUE,这里就有了一个问题。自己想的解决思路是再设置三个标志位,如果输入Integer.MIN_VALUE确实修改了就将标志位设置为true,但是这样会造成额外的开销。

        public int thirdMax(int[] nums) {
            int first = Integer.MIN_VALUE, second = Integer.MIN_VALUE, third = Integer.MIN_VALUE;
            for (int i : nums) {
                if (i < second && i > third) {
                    third = i;
                } else if (first > i && i > second) {
                    third = second;
                    second = i;
                } else if (i > first) {
                    third = second;
                    second = first;
                    first = i;
                }
            }
            return third == Integer.MIN_VALUE ? first : third;
        }

      3.解决问题的方法:将int类型改成Integer类型即可,其他完全一样,这样在return中就可以使用third==null?来进行判断。

      不过由于考虑到初始时first,second,third为null时直接替换,在if条件中加上了first == null ||与条件,这就会发生另外一种情况,就是{2,2,3,1}时,第二个2会直接进入到second,也就是无法去除重复元素,因此需要在前面加上一条判断语句, if (i.equals(first) || i.equals(second) || i.equals(third)) continue;,即如果和三个中的其中一个相同就直接退出循环。

        public int thirdMax(int[] nums) {
            Integer first = null, second = null, third = null;
            for (Integer i : nums) {
                if (i.equals(first) || i.equals(second) || i.equals(third)) continue;
                if (first == null || i > first) {
                    third = second;
                    second = first;
                    first = i;
                } else if (second == null || (first > i && i > second)) {
                    third = second;
                    second = i;
                } else if (third == null || second > i && i > third) {
                    third = i;
                }
            }
            return third == null ? first : third;
        }

      十、(考虑完各种情况)665. Non-decreasing Array

    输入: [4,2,3]
    输出: True
    解释: 你可以通过把第一个4变成1来使得它成为一个非递减数列。
    
    输入: [4,2,1]
    输出: False
    解释: 你不能在只改变一个元素的情况下将其变为非递减数列。

      1.思路:主要是要分清各种情况

      首先,定位到A[p-1]>A[p],如果p不是唯一的或者不存在,那么就是false。

      定位到之后,分析下面的情况:

    • p == -1:整个数组本身就是非递减数列。
    • p ==  1:也就是nums的nums[0] > nums[1],这个时候,只要让nums[0] = nums[1]
    • p == nums.length - 1:也就是nums的nums[nums.length - 2] > nums[nums.length - 1],这个时候,只要让最后一个点的值大于或等于倒数第二个点的值即可。
    • 如果nums[p-2]、nums[p-1]、nums[p]、nums[p+1]都存在的情况下:
    • nums[p-2] <= nums[p]:类似于{1,3,2,4}这种情况,可以把3变成1和2之间的数。
    • nums[p-1] <= nums[p+1]:类似于{1,3,2,4}这种情况,也可以把2变成3和4之间的数。

      2.代码:需要注意的是,由于最多只能改变一个数的值,因此,

      for循环中的if-else语句就是判断是否有两个或两个以上的值满足要求,如果是,就返回false。也就是说,p只能被赋值一次!

        public boolean checkPossibility(int[] nums) {
            int p = -1;
            for (int i = 1; i < nums.length; i++) {
                if (nums[i-1] > nums[i]) {
                    if (p != - 1) return false;
                    else p = i;
                }
            }
            return (p == -1 || p == 1 || p == nums.length-1 || nums[p-2] <= nums[p] || nums[p-1] <= nums[p+1]);
        }

      十一、739. Daily Temperatures

      十二、565.Array Nesting 854 / 856 test cases passed

    输入: A = [5,4,0,3,1,6,2]
    输出: 4
    解释: 
    A[0] = 5, A[1] = 4, A[2] = 0, A[3] = 3, A[4] = 1, A[5] = 6, A[6] = 2.
    
    其中一种最长的 S[K]:
    S[0] = {A[0], A[5], A[6], A[2]} = {5, 6, 2, 0}

      1.常规做法(O(n2) + O(1)),854 / 856 test cases passed,Time Limit Exceeded

        public int arrayNesting(int[] nums) {
            int maxlen = 0;
            int len = 0;
            int tmp = 0;
            for (int i = 0; i < nums.length; i++) {
                len = 1;
                tmp = nums[i];
                while (nums[tmp] != nums[i]) {
                    len++;
                    tmp = nums[tmp];
                }
                maxlen = Math.max(maxlen, len);
            }
            return maxlen;
        }

      2.更快的做法1(O(n) + O(n)):Using Visited Array  

      思路就是,例如A = [5,4,0,3,1,6,2],如果我们在A[0]=5的过程中已经确定了5, 6, 2, 0,那么我们将0,2,5,6这些位置进行标记,之后在遍历到2/5/6时直接跳过即可,

        public int arrayNesting(int[] nums) {
            boolean[] visited = new boolean[nums.length];
            int res = 0;
            for (int i = 0; i < nums.length; i++) {
                if (!visited[i]) {
                    int start = nums[i], count = 0;
                    do {
                        start = nums[start];
                        count++;
                        visited[start] = true;
                    }
                    while (start != nums[i]);
                    res = Math.max(res, count);
                }
            }
            return res;
        }

      3.更快的做法2(O(n) + O(1)):Without Using Extra Space

      思路就是,例如A = [5,4,0,3,1,6,2],如果我们在A[0]=5的过程中已经确定了5, 6, 2, 0,那么2/5/6在之后的遍历过程中可以不用了,也就是在原数组中修改这些位置上的值即可,反正也再也用不到了。

        public int arrayNesting(int[] nums) {
            int res = 0;
            for (int i = 0; i < nums.length; i++) {
                if (nums[i] != Integer.MAX_VALUE) {
                    int start = nums[i], count = 0;
                    while (nums[start] != Integer.MAX_VALUE) {
                        int temp = start;
                        start = nums[start];
                        count++;
                        nums[temp] = Integer.MAX_VALUE;
                    }
                    res = Math.max(res, count);
                }
            }
            return res;
        }

      十三、medium 529(DFS+BFS)

      1.

        public char[][] updateBoard(char[][] board, int[] click) {
            int m = board.length, n = board[0].length;
            int row = click[0], col = click[1];
            
            if (board[row][col] == 'M') {
                board[row][col] = 'X';
            } else {
                int count = 0;
                for (int i = -1; i < 2; i++) {
                    for (int j = -1; j < 2; j++) {
                        if (i == 0 && j == 0) continue;
                        int r = row + i, c = col + j;
                        if (r < 0 || r >= m || c < 0 || c >= n) continue;
                        if (board[r][c] == 'M' || board[r][c] == 'X') count++;
                    }
                }
                if (count > 0) {
                    board[row][col] = (char)(count + '0');
                } else {
                    board[row][col] = 'B';
                    for (int i = -1; i < 2; i++) {
                        for (int j = -1; j < 2; j++) {
                            if (i == 0 && j == 0) continue;
                            int r = row + i, c = col + j;
                            if (r < 0 || r >= m || c < 0 || c < 0 || c >= n) continue;
                            if (board[r][c] == 'E') updateBoard(board, new int[] {r, c});
                        }
                    }
                }
            }
            return board;
        }

      十四、

  • 相关阅读:
    Android 查看APK文件的签名算法
    Android 查看App冷启动时间/热启动时间/页面打开时间
    Android 查看Apk签名方式V1和V2
    Android App启动速度优化
    Android SharedPreferences中apply和commit的效率差距
    Gralde 网络代理
    Git 将子文件夹分离为一个新的库
    Fabric-Crashlytics-Android 注意点
    Gradle编译失败 generating the main dex list
    Gralde 同步失败
  • 原文地址:https://www.cnblogs.com/BigJunOba/p/9568728.html
Copyright © 2011-2022 走看看