二维数组

1. 旋转矩阵

给你一幅由 N × N 矩阵表示的图像,其中每个像素的大小为 4 字节。请你设计一种算法,将图像旋转 90 度。

不占用额外内存空间能否做到?

 

示例 1:

给定 matrix =
[
[1,2,3],
[4,5,6],
[7,8,9]
],

原地旋转输入矩阵,使其变为:
[
[7,4,1],
[8,5,2],
[9,6,3]
]
示例 2:

给定 matrix =
[
[ 5, 1, 9,11],
[ 2, 4, 8,10],
[13, 3, 6, 7],
[15,14,12,16]
],

原地旋转输入矩阵,使其变为:
[
[15,13, 2, 5],
[14, 3, 4, 1],
[12, 6, 8, 9],
[16, 7,10,11]
]

 

解题思路:先把数组上下按中心轴进行对位翻转,再进行斜对角的交换。

public class RotateArray {
public void rotate(int[][] matrix) {
int length = matrix.length;

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

for(int i = 0; i < length; i++) {
for(int j = 0 ;j <= i; j++) {
int temp = matrix[i][j];
matrix[i][j] = matrix[j][i];
matrix[j][i] = temp;
}
}

}
}

2.  零矩阵

编写一种算法,若M × N矩阵中某个元素为0,则将其所在的行与列清零。

示例 1:

输入:
[
[1,1,1],
[1,0,1],
[1,1,1]
]
输出:
[
[1,0,1],
[0,0,0],
[1,0,1]
]
示例 2:

输入:
[
[0,1,2,0],
[3,4,5,2],
[1,3,1,5]
]
输出:
[
[0,0,0,0],
[0,4,5,0],
[0,3,1,0]
]

解题思路:

1. 遍历整个矩阵,如果 matrix[i][j] == 0 就将第 i 行和第 j 列的第一个元素标记。
2. 第一行和第一列的标记是相同的,都是 matrix[0][0],所以需要一个额外的变量告知第一列是否被标记,同时用 matrix[0][0] 继续表示第一行的标记。
3. 然后,从第二行第二列的元素开始遍历,如果第 r 行或者第 c 列被标记了,那么就将 matrix[r][c] 设为 0。
4. 然后我们检查是否 matrix[0][0] == 0 ,如果是则赋值第一行的元素为零。
5. 然后检查第一列是否被标记,如果是则赋值第一列的元素为零。

class Solution {

    public void setZeroes(int[][] matrix) {
        int row = matrix.length;
        int column = matrix[0].length;
        boolean isCol = false;

        for(int i = 0; i < row; i++) {
            if(matrix[i][0] == 0){
                isCol = true;
            }

            for(int j = 1; j < column; j++) {
                if(matrix[i][j] == 0) {
                    matrix[i][0] = 0;
                    matrix[0][j] = 0;
                }
            }
        }

        for(int i = 1; i < row; i++) {
            for(int j = 1; j < column; j++){
                if(matrix[i][0] == 0 || matrix[0][j] == 0) {
                    matrix[i][j] = 0;
                }
            }
        }

        if(matrix[0][0] == 0){
            for(int j = 1; j < column; j++) {
                matrix[0][j] = 0;
            }
        }
        if(isCol) {
            for(int i = 0; i < row; i++) {
                matrix[i][0] = 0;
            }
        }
    }
}
 
3.

方法一:对角线迭代和翻转
思路

在第一行最后一列的元素作为起点的对角线上,对于给定元素 [i, j][i,j],可以向右移动一行向上移动一列沿对角线向上移动 [i - 1, j + 1][i−1,j+1],也可以向左移动一行向下移动一列沿对角线向下移动 [i + 1, j - 1][i+1,j−1]。注意:这种移动方式仅适用于从右往左的对角线。

该问题比原始问题简单,没有考虑对角线打印顺序的情况。因此,这就是简化问题需要修改的地方。

将元素添加到最终结果数组之前,只需要翻转奇数对角线上的元素顺序即可。例如:从左边开始的第三条对角线 [3, 7, 11],将这些元素添加到最后结果之前先翻转为 [11, 7, 3] 再添加即可。

public class RecursiveArray {
public int[] findDiagonalOrder(int[][] matrix) {
if(matrix.length <= 0) {
return new int[0];
}
int row = matrix.length;
int column = matrix[0].length;
int[] result = new int[row * column];
List<Integer> tempList = new ArrayList<Integer>();
int k = 0;

for(int i = 0; i < row + column - 1; i++) {
tempList.clear();
int rowIndex = (i < column) ? 0 : i - column + 1;
int columnIndex = i < column ? i : column - 1;

while(rowIndex < row && columnIndex >= 0) {
tempList.add(matrix[rowIndex][columnIndex]);
rowIndex++;
columnIndex--;
}

if(i % 2 == 0) {
Collections.reverse(tempList);
}

for(int num : tempList) {
result[k++] = num;
}
}
return result;
}

}

 

4. 区间列表的交集

给定两个由一些 闭区间 组成的列表,每个区间列表都是成对不相交的,并且已经排序。

返回这两个区间列表的交集。

(形式上,闭区间 [a, b](其中 a <= b)表示实数 x 的集合,而 a <= x <= b。两个闭区间的交集是一组实数,要么为空集,要么为闭区间。例如,[1, 3] 和 [2, 4] 的交集为 [2, 3]。)

 

示例:

 

输入:A = [[0,2],[5,10],[13,23],[24,25]], B = [[1,5],[8,12],[15,24],[25,26]]
输出:[[1,2],[5,5],[8,10],[15,23],[24,24],[25,25]]

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/interval-list-intersections
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

 

解题思路:前提,两个数组是排好序的数组。用双指针循环遍历,如果两个时间段的最大开始时间和最小结束时间,如果最大开始时间小于最小结束时间,则说明两个时间段有交集。取这个最大开始时间和最小结束时间作为时间段存起来。然后把结束时间段早的数组向后移一位。

class Solution {
    public int[][] intervalIntersection(int[][] firstList, int[][] secondList) {
        List<int[]> interRange = new ArrayList<>();

        int i = 0, j = 0;

        while(i < firstList.length && j < secondList.length) {
            int start = Math.max(firstList[i][0], secondList[j][0]);
            int end = Math.min(firstList[i][1], secondList[j][1]);

            if(start <= end) {
                int[] range = new int[]{start, end};
                interRange.add(range);
            }
            
            if(firstList[i][1] < secondList[j][1]) {
                i++;
            } else {
                j++;
            }
        }

        int[][] result = new int[interRange.size()][];
        for(int k = 0; k < interRange.size(); k++) {
            result[k] = interRange.get(k);
        }
        return result;
    }
}
 

5. 二维数组中的查找

在一个 n * m 的二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个高效的函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。

 

示例:

现有矩阵 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]
]
给定 target = 5,返回 true。

给定 target = 20,返回 false

作者:Krahets
链接:https://leetcode-cn.com/leetbook/read/illustration-of-algorithm/5v76yi/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

 

解题思路: 因为二维数组是

 

class Solution {
    public boolean findNumberIn2DArray(int[][] matrix, int target) {
        if(matrix.length == 0) {
            return false;
        }
        int row = matrix.length - 1;
        int column = matrix[0].length - 1;
        int j = 0;
        while(row >= 0 && j <= column) {
            if(matrix[row][j] == target) {
                return true;
            } 
            if(matrix[row][j] > target) {
                row--;
                continue;
            }
            if(matrix[row][j] < target) {
                j++;
            }
        }

        return false;
    }
}
 

假设有打乱顺序的一群人站成一个队列,数组 people 表示队列中一些人的属性(不一定按顺序)。每个 people[i] = [hi, ki] 表示第 i 个人的身高为 hi ,前面 正好 有 ki 个身高大于或等于 hi 的人。

请你重新构造并返回输入数组 people 所表示的队列。返回的队列应该格式化为数组 queue ,其中 queue[j] = [hj, kj] 是队列中第 j 个人的属性(queue[0] 是排在队列前面的人)。

 

示例 1:

输入:people = [[7,0],[4,4],[7,1],[5,0],[6,1],[5,2]]
输出:[[5,0],[7,0],[5,2],[6,1],[4,4],[7,1]]
解释:
编号为 0 的人身高为 5 ,没有身高更高或者相同的人排在他前面。
编号为 1 的人身高为 7 ,没有身高更高或者相同的人排在他前面。
编号为 2 的人身高为 5 ,有 2 个身高更高或者相同的人排在他前面,即编号为 0 和 1 的人。
编号为 3 的人身高为 6 ,有 1 个身高更高或者相同的人排在他前面,即编号为 1 的人。
编号为 4 的人身高为 4 ,有 4 个身高更高或者相同的人排在他前面,即编号为 0、1、2、3 的人。
编号为 5 的人身高为 7 ,有 1 个身高更高或者相同的人排在他前面,即编号为 1 的人。
因此 [[5,0],[7,0],[5,2],[6,1],[4,4],[7,1]] 是重新构造后的队列。
示例 2:

输入:people = [[6,0],[5,0],[4,0],[3,2],[2,2],[1,4]]
输出:[[4,0],[5,0],[2,2],[3,2],[1,4],[6,0]]
 

提示:

1 <= people.length <= 2000
0 <= hi <= 106
0 <= ki < people.length
题目数据确保队列可以被重建

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/queue-reconstruction-by-height
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

 

 解题思路: 按身高从高往低排序。然后按学生的位置插入。因为身高高的先被排在前面,所以后面插入相同位置的数会排在它前面。

class Solution {
    public int[][] reconstructQueue(int[][] people) {
        Arrays.sort(people, (p1,p2) -> {
            if(p1[0] == p2[0]) {
                return p1[1] - p2[1];
            }
            return p2[0] - p1[0];
        });

        List<int[]> stu = new LinkedList();
        for(int[] peo : people) {
            stu.add(peo[1], peo);
        }
        
        return stu.toArray(new int[stu.size()][]);

    }
}
 
7. 工时比较
 
用一个二维数组表示工厂每个员工每周的工时,如下所示
 
 
10 15 25
20 26 17
16 30 23
 
 
 
 
 
 
比较每一个员工每行每列比该员工工时大的员工数,每行每列不存在相同的数。比如b[0][0]工时为0, 比较第一行有2个员工比它大,比较第一列有2个员工比他大。则结果为4. b[0][1], 同行中有一个比他大,同列中有2个比他大,结果为3。 比较数组中所有的值。
 
此题有时间限制。
 
解题思路:此题如果用暴力解法,没法满足时间限制,会返回超出时间限制。我们发现每行每列如果通过一次比较后就把结果都存储起来,接下来把结果填回数组,就可以减少重复的比较。
我们使用PriorityQueue堆来存储每行每列的元素,并且按从小到大的顺讯排列。小顶堆的第一个元素就是每行每列的最小值,那他肯定比同行中其他员工的工时低,即为列的数量-1;同理弹出的第二个元素肯定比后边同行其他员工低,即为列的数量-2. 一次类推。
最后该单元格为行的数量加上列的数量。
 
进阶:如果每行每列有相同工时。
 
方法一:
public class CompareHours {
public static int[][] cmpScores(int[][] scores) {
if(scores.length == 0){
return scores;
}
int rows = scores.length;
int columns = scores[0].length;
int[][] result = new int[rows][columns];

PriorityQueue<ScoreIndex>[] rowQueues = new PriorityQueue[rows];
PriorityQueue<ScoreIndex>[] colQueues = new PriorityQueue[columns];

for(int i = 0; i < rows; i++){
rowQueues[i] = new PriorityQueue<>(Comparator.comparingInt(a -> a.score));
}

for(int j = 0; j < columns; j++) {
colQueues[j] = new PriorityQueue<>(Comparator.comparingInt(a -> a.score));
}

for(int k = 0 ; k < rows; k++) {
PriorityQueue<ScoreIndex> rowQueue = rowQueues[k];
for(int m = 0; m < columns; m++) {
PriorityQueue<ScoreIndex> colQueue = colQueues[m];
rowQueue.add(new ScoreIndex(scores[k][m], m));
colQueue.add(new ScoreIndex(scores[k][m], k));
}
}

for(int i = 0; i < rowQueues.length; i++) {
PriorityQueue<ScoreIndex> temp = rowQueues[i];
int k = 0;
while(!temp.isEmpty()) {
k++;
ScoreIndex scoreIndex = temp.poll();
result[i][scoreIndex.index] = columns - k;
}
}

for(int j = 0; j < colQueues.length; j++) {
PriorityQueue<ScoreIndex> temp = colQueues[j];
int k = 0;
while(!temp.isEmpty()) {
k++;
ScoreIndex scoreIndex = temp.poll();
result[scoreIndex.index][j] += rows - k;
}
}

return result;
}

static class ScoreIndex {
int score;
int index;

public ScoreIndex(int score, int index){
this.score = score;
this.index = index;
}
}

public static void main(String[] args) {
int length = 2000;

int [][] source = new int[length][length];

for(int i = 0; i < length; i++) {
for(int j = 0; j < length; j++) {
source[i][j] = new Random().nextInt(length);
}
}

long start = System.currentTimeMillis();
int[][] result = cmpScores(source);
System.out.println(System.currentTimeMillis() - start);
}
}

方法二: 每天的工时其实是有最大值的,要小于60小时。此时可以用数组能更简洁。

public int[][] compareTimes(int[][] scores) {
        int[] baseTime = new int[60];

        int rows =  scores.length;
        int cols = scores[0].length;
        int result[][] = new int[rows][cols];

        for(int i = 0 ; i < rows; i++) {
            Arrays.fill(baseTime, 0);
            for(int j = 0; j < cols; j++) {
          //把相应的值的计数存入数组, 索引即为该值。 baseTime[scores[i][j]]
+= 1; } for(int k = 0; k < cols; k++) {
          //getCount获取比当前值大的数字个数 result[i][k]
+= getCount(baseTime, scores[i][k]); } } for(int j = 0 ; j < cols; j++) { Arrays.fill(baseTime, 0); for(int i = 0; i < rows; i++) { baseTime[scores[i][j]] += 1; } for(int k = 0; k < rows; k++) { result[k][j] += getCount(baseTime, scores[k][j]); } } return result; } public int getCount(int[] baseTime, int target) { int count = 0; int index = target + 1; while(index < baseTime.length) { if(baseTime[index] > 0) { count += baseTime[index]; } index++; } return count; }

 




8.螺旋矩阵

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


示例 1:


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


示例 2:


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


来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/spiral-matrix
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

 

解题思路: 螺旋查找。先从左往右,再从上往下,再从右往左,再从下往上。

 

class Solution {
    public List<Integer> spiralOrder(int[][] matrix) {
        if(matrix == null || matrix.length == 0) {
            return new ArrayList<Integer>();
        }
        int l = 0;
        int r = matrix[0].length -1;
        int t = 0;
        int b = matrix.length - 1;

        List<Integer> res = new ArrayList<>();

        while(true) {
            //从左往右
            for(int i = l; i <= r; i++) {
                res.add(matrix[t][i]);
            }
            if(++t > b) {
                break;
            }
            
            //从上往下
            for(int j = t; j <= b; j++) {
                res.add(matrix[j][r]);
            }
            
            if(l > --r) {
                break;
            }
            //从右向左
            for(int k = r; k >= l; k--) {
                res.add(matrix[b][k]);
            }
            if(t > --b) {
                break;
            }
    
   //从下往上
            for(int m = b; m >= t; m--) {
                res.add(matrix[m][l]);
            }

            if(++l > r) {
                break;
            }
        }

        return res;
    }
}
 

560. 和为K的子数组
给定一个整数数组和一个整数 k,你需要找到该数组中和为 k 的连续的子数组的个数。

示例 1 :

输入:nums = [1,1,1], k = 2
输出: 2 , [1,1] 与 [1,1] 为两种不同的情况。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/subarray-sum-equals-k
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

class Solution {
  public int subarraySum(int[] nums, int k) {
    int count = 0;
    int len = nums.length;
    int[] res = new int[len+1];
    res[0] = 0;

    for(int i = 0; i < len; i++) {
      res[i + 1] = res[i] + nums[i];
    }

    for(int i = 1; i <= len; i++) {
      for(int j = 0; j < i; j++) {
        if(res[i] - res[j] == k) {
          count++;
        }
      }
    }

    return count;
  }
}

posted @ 2020-12-19 18:45  闪闪的星光  阅读(136)  评论(0)    收藏  举报