leetcode: 数组

Posted strong

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了leetcode: 数组相关的知识,希望对你有一定的参考价值。

1. longest-consecutive-sequence

Given an unsorted array of integers, find the length of the longest consecutive elements sequence.

For example,
Given[100, 4, 200, 1, 3, 2],
The longest consecutive elements sequence is[1, 2, 3, 4]. Return its length:4.

Your algorithm should run in O(n) complexity.

 

给定一个整形数组,求出最长的连续序列。例如数组[100,4,200,1,3,2],最长的连续序列长度为[1,2,3,4],长度为4。要求时间复杂度为O(n)。

 

排序的话至少要O(nlgn) 的复杂度。O(n)的复杂度,目前只找到了使用hash来解决的方案,add, remove, contains 等方法的复杂度都是 O(1),因此两次遍历的操作复杂度为 O(n)。

public static int longestConsecutive(int[] num) {
    // if array is empty, return 0
    if (num.length == 0) {
        return 0;
    }
 
    Set<Integer> set = new HashSet<Integer>();
    int max = 1;
 
    for (int e : num)
        set.add(e);
 
    for (int e : num) {
        int left = e - 1;
        int right = e + 1;
        int count = 1;
 
        while (set.contains(left)) {
            count++;
            set.remove(left);
            left--;
        }
 
        while (set.contains(right)) {
            count++;
            set.remove(right);
            right++;
        }
 
        max = Math.max(count, max);
    }
 
    return max;
}
View Code

 

 

2. surrounded-regions

Given a 2D board containing\'X\'and\'O\', capture all regions surrounded by\'X\'.

A region is captured by flipping all\'O\'s into\'X\'s in that surrounded region .

For example,

X X X X
X O O X
X X O X
X O X X

After running your function, the board should be:

X X X X
X X X X
X X X X
X O X X

典型的BFS题目。遍历每个字符,如果是“O”,则从当前字符开始BFS遍历,如果周围也是“O”则加入当前遍历的队列,知道遍历完所有相邻的“O”,于此同时,判断每个O是否是被包围的,只有由一个O是没有被包围的,则当前遍历的O的集合都是没有被包围的,因为这些O都是相连的。

当然,此题使用DFS也可以,只是测试数据过大,提交时StackOverFlow.

 

1)BFS 广度优先搜索

public class Solution {
    // use a queue to do BFS
    private Queue<Integer> queue = new LinkedList<Integer>();
 
    public void solve(char[][] board) {
        if (board == null || board.length == 0)
            return;
 
        int m = board.length;
        int n = board[0].length;
 
        // merge O\'s on left & right boarder
        for (int i = 0; i < m; i++) {
            if (board[i][0] == \'O\') {
                bfs(board, i, 0);
            }
 
            if (board[i][n - 1] == \'O\') {
                bfs(board, i, n - 1);
            }
        }
 
        // merge O\'s on top & bottom boarder
        for (int j = 0; j < n; j++) {
            if (board[0][j] == \'O\') {
                bfs(board, 0, j);
            }
 
            if (board[m - 1][j] == \'O\') {
                bfs(board, m - 1, j);
            }
        }
 
        // process the board
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (board[i][j] == \'O\') {
                    board[i][j] = \'X\';
                } else if (board[i][j] == \'#\') {
                    board[i][j] = \'O\';
                }
            }
        }
    }
 
    private void bfs(char[][] board, int i, int j) {
        int n = board[0].length;
 
        // fill current first and then its neighbors
        fillCell(board, i, j);
 
        while (!queue.isEmpty()) {
            int cur = queue.poll();
            int x = cur / n;
            int y = cur % n;
 
            fillCell(board, x - 1, y);
            fillCell(board, x + 1, y);
            fillCell(board, x, y - 1);
            fillCell(board, x, y + 1);
        }
    }
 
    private void fillCell(char[][] board, int i, int j) {
        int m = board.length;
        int n = board[0].length;
        if (i < 0 || i >= m || j < 0 || j >= n || board[i][j] != \'O\')
            return;
 
        // add current cell is queue & then process its neighbors in bfs
        queue.offer(i * n + j);
        board[i][j] = \'#\';    // 用#标识要保留的O
    }
}
View Code

 

2)DFS深度优先搜索

public void solve(char[][] board) {
    if(board == null || board.length==0) 
        return;
 
    int m = board.length;
    int n = board[0].length;
 
    //merge O\'s on left & right boarder
    for(int i=0;i<m;i++){
        if(board[i][0] == \'O\'){
            merge(board, i, 0);
        }
 
        if(board[i][n-1] == \'O\'){
            merge(board, i,n-1);
        }
    }
 
    //merge O\'s on top & bottom boarder
    for(int j=0; j<n; j++){
         if(board[0][j] == \'O\'){
            merge(board, 0,j);
        }
 
        if(board[m-1][j] == \'O\'){
            merge(board, m-1,j);
        }
    }
 
    //process the board
    for(int i=0;i<m;i++){
        for(int j=0; j<n; j++){
            if(board[i][j] == \'O\'){
                board[i][j] = \'X\';
            }else if(board[i][j] == \'#\'){
                board[i][j] = \'O\';
            }
        }
    }
}
 
public void merge(char[][] board, int i, int j){
    if(i<0 || i>=board.length || j<0 || j>=board[0].length) 
        return;
 
    if(board[i][j] != \'O\')
        return;
 
    board[i][j] = \'#\';
 
   // 递归实现深度优先搜索
    merge(board, i-1, j);
    merge(board, i+1, j);
    merge(board, i, j-1);
    merge(board, i, j+1);
}
View Code

 

 

3. Best Time to Buy and Sell Stock  I II III 

3.1 Best Time to Buy and Sell Stock  I 

Description: Say you have an array for which the ith element is the price of a given stock on day i. If you were only permitted to complete at most one transaction (ie, buy one and sell one share of the stock), design an algorithm to find
the maximum profit.

题意:用一个数组表示股票每天的价格,数组的第i个数表示股票在第i天的价格。 如果只允许进行一次交易,也就是说只允许买一支股票并卖掉,求最大的收益。

分析:动态规划法。从前向后遍历数组,记录当前出现过的最低价格,作为买入价格,并计算以当天价格出售的收益,作为可能的最大收益,整个遍历过程中,出现过的最大收益就是所求。

代码:O(n)时间,O(1)空间。

public class Solution {
    public int maxProfit(int[] prices) {
        if (prices.length < 2) return 0;
        
        int maxProfit = 0;
        int curMin = prices[0];
        
        for (int i = 1; i < prices.length; i++) {
            curMin = Math.min(curMin, prices[i]);
            maxProfit = Math.max(maxProfit, prices[i] - curMin);
        }
        
        return maxProfit;
    }
}
View Code

 

3.2 Best Time to Buy and Sell Stock  II

Description: Say you have an array for which the ith element is the price of a given stock on day i. Design an algorithm to find the maximum profit. You may complete as many transactions as you like (ie, buy one and sell one share of the stock multiple times). However, you may not engage in multiple transactions at the same time (ie, you must sell the stock before you buy again).

题目:用一个数组表示股票每天的价格,数组的第i个数表示股票在第i天的价格。  交易次数不限,   但一次只能交易一支股票,也就是说手上最多只能持有一支股票,求最大收益。

分析:贪心法。从前向后遍历数组,只要当天的价格高于前一天的价格,就算入收益。

代码:时间O(n),空间O(1)。

public class Solution {
    public int maxProfit(int[] prices) {
        if (prices.length < 2) return 0;
        
        int maxProfit = 0;
        for (int i = 1; i < prices.length; i++) {
            int diff = prices[i] - prices[i - 1];
            if (diff > 0) {
                maxProfit += diff;
            }
        }
        
        return maxProfit;
    }
}
View Code

 

3.3 Best Time to Buy and Sell Stock  III 

Description: Say you have an array for which the ith element is the price of a given stock on day i. Design an algorithm to find the maximum profit. You may complete at most two transactions. Note: You may not engage in multiple transactions at the same time (ie, you must sell the stock before you buy again).

题意:用一个数组表示股票每天的价格,数组的第i个数表示股票在第i天的价格。最多交易两次,手上最多只能持有一支股票,求最大收益。

分析:动态规划法。以第i天为分界线,计算第i天之前进行一次交易的最大收益preProfit[i],和第i天之后进行一次交易的最大收益postProfit[i],最后遍历一遍,max{preProfit[i] + postProfit[i]} (0≤i≤n-1)就是最大收益。第i天之前和第i天之后进行一次的最大收益求法同Best Time to Buy and Sell Stock I。

代码:时间O(n),空间O(n)。

public class Solution {
    public int maxProfit(int[] prices) {
        if (prices.length < 2) return 0;
        
        int n = prices.length;
        int[] preProfit = new int[n];
        int[] postProfit = new int[n];
        
        int curMin = prices[0];
        for (int i = 1; i < n; i++) {
            curMin = Math.min(curMin, prices[i]);
            preProfit[i] = Math.max(preProfit[i - 1], prices[i] - curMin);
        }
        
        int curMax = prices[n - 1];
        for (int i = n - 2; i >= 0; i--) {
            curMax = Math.max(curMax, prices[i]);
            postProfit[i] = Math.max(postProfit[i + 1], curMax - prices[i]);
        }
        
        int maxProfit = 0;
        for (int i = 0; i < n; i++) {
            maxProfit = Math.max(maxProfit, preProfit[i] + postProfit[i]);
        }
        
        return  maxProfit;
    }
}
View Code

 

 

4. convert-sorted-array-to-binary-search-tree

Given an array where elements are sorted in ascending order, convert it to a height balanced BST.

从给定的有序数组转成一个平衡二叉树(左子树<根结点<右子树)

/**
 * Definition for binary tree
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */

public class Solution {
    private TreeNode buildTree(int[] num, int start, int end) {
        if (start > end) {
            return null;
        }

        TreeNode node = new TreeNode(num[(start + end) / 2]);
        node.left = buildTree(num, start, (start + end) / 2 - 1);
        node.right = buildTree(num, (start + end) / 2 + 1, end);
        return node;
    }

    public TreeNode sortedArrayToBST(int[] num) {
        if (num == null) {
            return null;
        }
        return buildTree(num, 0, num.length - 1);
    }
}
View Code

 

5. plus-one

  Given a non-negative number represented as an array of digits, plus one to the number. 
  The digits are stored such that the most significant digit is at the head of the list. 

  给定一个用数组表示的一个数,对它进行加一操作。 
  每一个数位都存储在数组的一个位置上。数组下标从大到小表示数位从低位到高位。 

 

  直接求解,设置一个进位标志carry,初值为1,表示加1,从最低位开始tmp = a[x] + carry, 
a[x] = tmp%10,carry = tmp/10,如果carry不为0对下一位再进行操作,直到所有的数位处理完或者carray为0就退出,如果最后还有carray不为0说明整个数组要扩展一个数位。 

public class Solution{
    public int[] plusOne(int[] digits) {
    int len = digits.length;
    
    boolean flag = true; // 进位标记
 
    for (int i = len - 1; i >= 0; i--) {
        if (flag) {
            if (digits[i] == 9) {
                digits[i] = 0;
            } else {
                digits[i] = digits[i] + 1;
                flag = false;
            }
 
            if (i == 0 && digits[i] == 0) {
                int[] y = new int[len + 1];
                y[0] = 1;
                for (int j = 1; j <= len; j++) {
                    y[j] = digits[j - 1];
                }
                digits = y;
            }
        }
    }
 
    return digits;
}
}
View Code

 

 

6. search-a-2d-matrix

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

  • Integers in each row are sorted from left to right.
  • The first integer of each row is greater than the last integer of the previous row.

For example,

Consider the following matrix:

[
  [1,   3,  5,  7],
  [10, 11, 16, 20],
  [23, 30, 34, 50]
]

Given target =3, return true.

解法一:

从右上到左下进行搜索。时间复杂度 O(m + n)

解法二:

如果把第0行,第1行,第i行...第i+1行依次连接起来,使得2D数组被还原为1D数组,那么显然这个1D数组就被转化成为了一个排好序的数组。接下来普通的二分搜索就OK了。  时间复杂度lg(m * n) = lg(m) + lg(n)

// 二分法
public class Solution {
    public boolean searchMatrix(int[][] matrix, int target) {
        if(matrix==null || matrix.length==0 || matrix[0].length==0) 
            return false;
 
        int m = matrix.length;
        int n = matrix[0].length;
 
        int start = 0;
        int end = m*n-1;
 
        while(start<=end){
            int mid=(start+end)/2;
            int midX=mid/n;
            int midY=mid%n;
 
            if(matrix[midX][midY]==target) 
                return true;
 
            if(matrix[midX][midY]<target){
                start=mid+1;
            }else{
                end=mid-1;
            }
        }
 
        return false;
    }
}
View Code

 

 

7. rotate image

You are given an n x n 2D matrix representing an image.

Rotate the image by 90 degrees (clockwise).

Follow up:
Could you do this in-place?

 二维数组a[n][n] 顺时针旋转90度,  规律 :a[i][j]=a[n-1-j][i]

public class Solution {
    public void rotate(int[][] matrix) {
        if(matrix == null || matrix.length==0)
            return ;
 
        int m = matrix.length;
 
        int[][] result = new int[m][m];
 
        for(int i=0; i<m; i++){
            for(int j=0; j<m; j++){
                result[j][m-1-i] = matrix[i][j];
            }
        } 
 
       for(int i=0; i<m; i++){
            for(int j=0; j<m; j++){
                matrix[i][j] = result[i][j];
            }
        } 
    }
}
View Code

 

 

8. spiral-matrix

Given a matrix of m x n elements (mrows, n columns), return all elements of the matrix in spiral order.

For example,
Given the following matrix:

[
 [ 1, 2, 3 ],
 [ 4, 5, 6 ],
 [ 7, 8, 9 ]
]

You should return[1,2,3,6,9,8,7,4,5].

特殊情况: 只有一行或一列;  其他情况,从左到右,从上到下,从右到坐,从下到上,完成一轮,矩阵的长宽缩减2

public class Solution {
    public ArrayList<Integer> spiralOrder(int[][] matrix) {
        ArrayList<Integer> result = new ArrayList<Integer>();
 
        if(matrix == null || matrix.length == 0) return result;
 
        int m = matrix.length;
        int n = matrix[0].length;
 
        int x=0; 
        int y=0;
 
        while(m>0 && n>0){
 
            //if one row/column left, no circle can be formed
            if(m==1){
                for(int i=0; i<n; i++){
                    result.add(matrix[x][y++]);
                }
                break;
            }else if(n==1){
                for(int i=0; i<m; i++){
                    result.add(matrix[x++][y]);
                }
                break;
            }
 
            //below, process a circle
 
            //top - move right
            for(int i=0;i<n-1;i++){
                result.add(matrix[x][y++]);
            }
 
            //right - move down
            for(int i=0;i<m-1;i++){
                result.add(matrix[x++][y]);
            }
 
            //bottom - move left
            for(int i=0;i<n-1;i++){
                result.add(matrix[x][y--]);
            }
 
            //left - move up
            for(int i=0;i<m-1;i++){
                result.add(matrix[x--][y]);
            }
 
            x++;
            y++;
            m=m-2;
            n=n-2;
        }
 
        return result;
    }
}
View Code

 

 

9. merge-intervals

Given a collection of intervals, merge all overlapping intervals.

For example,
Given[1,3],[2,6],[8,10],[15,18],
return[1,6],[8,10],[15,18]

给定一个区间集合,合并有重叠的区间

 

 先对区间排序,按开始点进行排序,再一个个进行合并;如果结果集合为空或者当前interval与结果集合中最后一个interval不重叠,那么就直接将当前interval加入到结果中;如果发生了重叠,那么修改结果集合中的最后一个interval的右端点(改为当前interval的右端点或不修改)

/**
 * Definition for an interval.
 * public class Interval {
 *     int start;
 *     int end;
 *     Interval() { start = 0; end = 0; }
 *     Interval(int s, int e) { start = s; end = e; }
 * }
 */
 public List<Interval> merge(List<Interval> intervals) {
    List<Interval> list = new ArrayList<Interval>();
    Comparator<Interval> comparator = new Comparator<Interval>() {
        @Override
        public int compare(Interval o1, Interval o2) {
            if (o1.start == o2.start)
                return o1.end - o2.end;
            return o1.start - o2.start;
        }
    };
    Collections.sort(intervals, comparator);
    for (Interval interval : intervals)
        if (list.size() == 0 || list.get(list.size() - 1).end < interval.start)
            list.add(new Interval(interval.start, interval.end));
        else
            list.get(list.size() - 1).end = Math.max(interval.end, list.get(list.size() - 1).end);
    return list;
}
 
 
View Code

 

 

10. Merge Sorted Array

Given two sorted integer arrays A and B, merge B into A as one sorted array.

Note:
You may assume that A has enough space to hold additional elements from B. The number of elements initialized in A and B are m and n respectively.

考虑从后往前比较,这样就不会产生需要数据后移的问题了;同时考虑B数组还有剩余的情况。时间复杂度O(n+m)

public class Solution {
    public void merge(int A[], int m, int B[], int n) {
 
        while(m > 0 && n > 0){
            if(A[m-1] > B[n-1]){
                A[m+n-1] = A[m-1];
                m--;
            }else{
                A[m+n-1] = B[n-1];
                n--;
            }
        }
 
        while(n > 0){
            A[m+n-1] = B[n-1];
            n--;
        }
    }
}
View Code
public void merge(int A[], int m, int B[], int n) {
    int i = m - 1;
    int j = n - 1;
    int k = m + n - 1;
 
    while (k >= 0) {
        if (j < 0 || (i >= 0 && A[i] > B[j]))
            A[k--] = A[i--];
        else
            A[k--] = B[j--];
    }
}
View Code

 

 

11. 3sum-closest

Given an array S of n integers, find three integers in S such that the sum is closest to a given number, target. Return the sum of the three integers. You may assume that each input would have exactly one solution.

    For example, given array S = {-1 2 1 -4}, and target = 1.

    The sum that is closest to the target is 2. (-1 + 2 + 1 = 2).

先固定一个数,剩下的用2sum方法解决即可,采用两个指针从前后方向,时间复杂度O(n^2)

public int threeSumClosest(int[] nums, int target) {
    int min = Integer.MAX_VALUE;
    int result = 0;
 
    Arrays.sort(nums);
 
    for (int i = 0; i < nums.length; i++) {
        int j = i + 1;
        int k = nums.length - 1;
        while (j < k) {
            int sum = nums[i] + nums[j] + nums[k];
            int diff = Math.abs(sum - target);
 
            if(diff == 0) return sum;
 
            if (diff < min) {
                min = diff;
                result = sum;
            }
            if (sum <= target) {
                j++;
            } else {
                k--;
            }
        }
    }
 
    return result;
}
View Code

 

12. remove element

Given an array and a value, remove all instances of that value in place and return the new length.

The order of elements can be changed. It doesn\'t matter what you leave beyond the new length.

返回所有删除指定元素的数组

1)把原数组A的元素拷贝到新的数组中,A可以当做新的数组

public class Solution {  
    public int removeElement(int[] A, int elem) {  
        int newIndex = 0;  
        for (int oldIndex = 0; oldIndex < A.length; ++oldIndex) {  
            if (A[oldIndex] != elem) {  
                A[newIndex++] = A[oldIndex];  
            }   
            oldIndex++;
        }  
        return newIndex;  
    }  
}  
View Code

2)把不需要的元素放在原数组的尾部

public class Solution {  
    public int removeElement(int[] A, int elem) {  
        if (A.length ==0) return A.length;  
        //if (A.lenth == 1 && A[0] == elem) return 0;  
        //if (A.lenth == 1 && A[0] != elem) return 1;  
        int i = 0, j = A.length - 1;  
        //while (i < j) {  
        while (i <= j) {  
            if (A[i] == elem) {  
                int tmp = A[i];  
                A[i] = A[j];  
                A[j] = tmp;  
                --j;  
            } else {  
                ++i;  
            }  
        }  
        //return j; 因为while (i<=j)才结束,而不是while (i < j)才结束,所以这里返回j+1  
        return j + 1;  
    }  
}  
View Code

 

以上是关于leetcode: 数组的主要内容,如果未能解决你的问题,请参考以下文章

Leetcode.1024 视频拼接

VSCode自定义代码片段—— 数组的响应式方法

VSCode自定义代码片段10—— 数组的响应式方法

leetcode_1292. Maximum Side Length of a Square with Sum Less than or Equal to Threshold_[二维前缀和](代码片段

LeetCode 260 只出现一次的数字(超详细)

web代码片段