Leetcode-283. 移动零
把数组中的 0 移到末尾
输入: [0,1,0,3,12]
输出: [1,3,12,0,0]
说明:
- 必须在原数组上操作,不能拷贝额外的数组。
- 尽量减少操作次数。
解法:
- Java
class Solution {
public void moveZeroes(int[] nums) {
int i = 0;
for (int num: nums) {
if (num != 0) nums[i++] = num;
}
while (i<nums.length) nums[i++] = 0;
}
}
Leetcode-566. 重塑矩阵
改变矩阵维度
在MATLAB中,有一个非常有用的函数 reshape,它可以将一个矩阵重塑为另一个大小不同的新矩阵,但保留其原始数据。
给出一个由二维数组表示的矩阵,以及两个正整数r和c,分别表示想要的重构的矩阵的行数和列数。
重构后的矩阵需要将原始矩阵的所有元素以相同的行遍历顺序填充。
如果具有给定参数的reshape操作是可行且合理的,则输出新的重塑矩阵;否则,输出原始矩阵。
示例 1:
输入:
nums =
[[1,2],
[3,4]]
r = 1, c = 4
输出:
[[1,2,3,4]]
解释:
行遍历nums的结果是 [1,2,3,4]。新的矩阵是 1 * 4 矩阵, 用之前的元素值一行一行填充新矩阵。
示例 2:
输入:
nums =
[[1,2],
[3,4]]
r = 2, c = 4
输出:
[[1,2],
[3,4]]
解释:
没有办法将 2 * 2 矩阵转化为 2 * 4 矩阵。 所以输出原矩阵。
注意:
- 给定矩阵的宽和高范围在 [1, 100]。
- 给定的 r 和 c 都是正数。
解法:
- Java
class Solution {
public int[][] matrixReshape(int[][] nums, int r, int c) {
int m = nums.length, n = nums[0].length;
if (m*n != r*c) return nums;
int[][] res = new int[r][c];
int index = 0;
for (int i=0;i<r;i++) {
for (int j=0;j<c;j++) {
res[i][j] = nums[index/n][index%n];
index++;
}
}
return res;
}
}
Leetcode-485. 最大连续1的个数
给定一个二进制数组, 计算其中最大连续1的个数。
示例 1:
输入: [1,1,0,1,1,1]
输出: 3
解释: 开头的两位和最后的三位都是连续1,所以最大连续1的个数是 3.
注意:
- 输入的数组只包含 0 和1。
- 输入数组的长度是正整数,且不超过 10,000。
解法:
- Java
class Solution {
public int findMaxConsecutiveOnes(int[] nums) {
int max = 0, cur = 0;
for (int i=0;i<nums.length;i++) {
cur = nums[i]==0? 0: cur+1;
max = Math.max(max, cur);
}
return max;
}
}
Leetcode-240. 搜索二维矩阵 II
编写一个高效的算法来搜索 m x n 矩阵 matrix 中的一个目标值 target。该矩阵具有以下特性:
每行的元素从左到右升序排列。
每列的元素从上到下升序排列。
示例:
现有矩阵 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。
解法:从右上角开始遍历
- Java
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, n = matrix[0].length;
int row = 0, col = n-1;
while (row<m && col>=0) {
if (matrix[row][col]==target) {
return true;
} else if (target < matrix[row][col]) {
col--;
} else {
row++;
}
}
return false;
}
}
Leetcode-378. 有序矩阵中第K小的元素
给定一个 n x n 矩阵,其中每行和每列元素均按升序排序,找到矩阵中第k小的元素。
请注意,它是排序后的第k小元素,而不是第k个元素。
示例:
matrix = [
[ 1, 5, 9],
[10, 11, 13],
[12, 13, 15]
],
k = 8,
返回 13。
说明:
你可以假设 k 的值永远是有效的, 1 ≤ k ≤ n2 。
解法:二分法或者堆排序
https://leetcode.com/problems/kth-smallest-element-in-a-sorted-matrix/discuss/301357/Java-0ms-(added-Python-and-C%2B%2B)%3A-Easy-to-understand-solutions-using-Heap-and-Binary-Search
二分查找
cnt==k时,情况很可能是k-1, k, mid, k+1,也就是说第k小的数肯定在mid 的左边,所以这时候hi = mid - 1是没有问题的,如果出现mid直接等于k的情况,比如最后一个数由15换成17,要求第三小的数,那么mid直接等于9,这时候执行了hi = 8,这样cnt一直小于k,当lo=hi=8时,lo又回+1变回9,所以while中的<=就非常的关键了
- Java
class Solution {
public int kthSmallest(int[][] matrix, int k) {
int m = matrix.length, n = matrix[0].length;
int low = matrix[0][0], high = matrix[m-1][n-1];
while (low<=high) {
int mid = low + (high-low)/2;
int cnt = 0;
for (int i=0;i<m;i++) {
for (int j=0;j<n && matrix[i][j]<=mid;j++) {
cnt++;
}
}
if (cnt<k) {
low = mid + 1;
} else {
high = mid - 1;
}
}
return low;
}
}
堆排序
- Java
把所有列的最小值添加进最小堆中,每次remove掉最小的元素,再把最小的元素的那列的下一个元素添加到最小堆中计算,总共推出k-1个最小值后,下一个就是第k个最小的
class Solution {
public int kthSmallest(int[][] matrix, int k) {
int m = matrix.length, n = matrix[0].length;
PriorityQueue<Tuple> pq = new PriorityQueue<>();
for (int j=0;j<n;j++) pq.add(new Tuple(0, j, matrix[0][j]));
for (int i=0;i<k-1;i++) {
Tuple t = pq.remove();
if (t.x == m-1) continue;
pq.add(new Tuple(t.x+1, t.y, matrix[t.x+1][t.y]));
}
return pq.remove().val;
}
class Tuple implements Comparable<Tuple> {
int x, y, val;
public Tuple(int x, int y, int val) {
this.x = x;
this.y = y;
this.val = val;
}
@Override
public int compareTo(Tuple that) {
return this.val-that.val;
}
}
}
Leetcode-645. 错误的集合
一个数组元素在 [1, n] 之间,其中一个数被替换为另一个数,找出重复的数和丢失的数
集合 S 包含从1到 n 的整数。不幸的是,因为数据错误,导致集合里面某一个元素复制了成了集合里面的另外一个元素的值,导致集合丢失了一个整数并且有一个元素重复。
给定一个数组 nums 代表了集合 S 发生错误后的结果。你的任务是首先寻找到重复出现的整数,再找到丢失的整数,将它们以数组的形式返回。
示例 1:
输入: nums = [1,2,2,4]
输出: [2,3]
注意:
- 给定数组的长度范围是 [2, 10000]。
- 给定的数组是无序的。
解法:最直接的方法是先对数组进行排序,这种方法时间复杂度为 O(NlogN)。本题可以以 O(N) 的时间复杂度、O(1) 空间复杂度来求解。主要思想是通过交换数组元素,使得数组上的元素在正确的位置上。
- Java
class Solution {
public int[] findErrorNums(int[] nums) {
for (int i=0;i<nums.length;i++) {
while (nums[i]!=i+1 && nums[nums[i]-1]!=nums[i]) swap(nums, i, nums[i]-1);
}
for (int i=0;i<nums.length;i++) {
if (nums[i] != i+1) return new int[]{
nums[i], i+1};
}
return null;
}
private void swap(int[] nums, int i, int j) {
int tmp = nums[i];
nums[i] = nums[j];
nums[j] = tmp;
}
}
Leetcode-287. 寻找重复数
找出数组中重复的数,数组值在 [1, n] 之间
给定一个包含 n + 1 个整数的数组 nums,其数字都在 1 到 n 之间(包括 1 和 n),可知至少存在一个重复的整数。假设只有一个重复的整数,找出这个重复的数。
示例 1:
输入: [1,3,4,2,2]
输出: 2
示例 2:
输入: [3,1,3,4,2]
输出: 3
说明:
- 不能更改原数组(假设数组是只读的)。
- 只能使用额外的 O(1) 的空间。
- 时间复杂度小于 O(n2) 。
- 数组中只有一个重复的数字,但它可能不止重复出现一次。
解法:
二分查找法
- Java
正常情况下,1~n中的全部整数,<=n的应该有n个,所以当cnt==mid时,说明1-mid是没有重复数的,重复数肯定在mid之后
是没有
class Solution {
public int findDuplicate(int[] nums) {
int l = 1, h = nums.length-1;
while (l<=h) {
int mid = l + (h-l)/2;
int cnt = 0;
for (int i=0;i<nums.length;i++) {
if (nums[i] <= mid) cnt++;
}
if (cnt > mid) h = mid-1;
else l = mid+1;
}
return l;
}
}
快慢指针法
类似于有环链表中找出环的入口
- Java
public int findDuplicate(int[] nums) {
int slow = nums[0], fast = nums[nums[0]];
while (slow != fast) {
slow = nums[slow];
fast = nums[nums[fast]];
}
fast = 0;
while (slow != fast) {
slow = nums[slow];
fast = nums[fast];
}
return slow;
}
Leetcode-667. 优美的排列 II
数组相邻差值的个数
给定两个整数 n 和 k,你需要实现一个数组,这个数组包含从 1 到 n 的 n 个不同整数,同时满足以下条件:
① 如果这个数组是 [a1, a2, a3, … , an] ,那么数组 [|a1 - a2|, |a2 - a3|, |a3 - a4|, … , |an-1 - an|] 中应该有且仅有 k 个不同整数;.
② 如果存在多种答案,你只需实现并返回其中任意一种.
示例 1:
输入: n = 3, k = 1
输出: [1, 2, 3]
解释: [1, 2, 3] 包含 3 个范围在 1-3 的不同整数, 并且 [1, 1] 中有且仅有 1 个不同整数 : 1
示例 2:
输入: n = 3, k = 2
输出: [1, 3, 2]
解释: [1, 3, 2] 包含 3 个范围在 1-3 的不同整数, 并且 [2, 1] 中有且仅有 2 个不同整数: 1 和 2
提示:
- n 和 k 满足条件 1 <= k < n <= 104.
解法:
让前 k+1 个元素构建出 k 个不相同的差值,序列为:1 k+1 2 k 3 k-1 … k/2 k/2+1.
- Java
public int[] constructArray(int n, int k) {
int[] ret = new int[n];
ret[0] = 1;
for (int i = 1, interval = k; i <= k; i++, interval--) {
ret[i] = i % 2 == 1 ? ret[i - 1] + interval : ret[i - 1] - interval;
}
for (int i = k + 1; i < n; i++) {
ret[i] = i + 1;
}
return ret;
}
Leetcode-697. 数组的度
给定一个非空且只包含非负数的整数数组 nums, 数组的度的定义是指数组里任一元素出现频数的最大值。
你的任务是找到与 nums 拥有相同大小的度的最短连续子数组,返回其长度。
示例 1:
输入: [1, 2, 2, 3, 1]
输出: 2
解释:
输入数组的度是2,因为元素1和2的出现频数最大,均为2.
连续子数组里面拥有相同度的有如下所示:
[1, 2, 2, 3, 1], [1, 2, 2, 3], [2, 2, 3, 1], [1, 2, 2], [2, 2, 3], [2, 2]
最短连续子数组[2, 2]的长度为2,所以返回2.
示例 2:
输入: [1,2,2,3,1,4,2]
输出: 6
注意:
- nums.length 在1到50,000区间范围内。
- nums[i] 是一个在0到49,999范围内的整数。
解法:
分别计算各个数字的度,记录第一次和最后一次出现的位置
- Java
class Solution {
public int findShortestSubArray(int[] nums) {
Map<Integer, Integer> numsCnt = new HashMap<>();
Map<Integer, Integer> numsLastIndex = new HashMap<>();
Map<Integer, Integer> numsFirstIndex = new HashMap<>();
for (int i=0;i<nums.length;i++) {
int num = nums[i];
numsCnt.put(num, numsCnt.getOrDefault(num, 0)+1);
numsLastIndex.put(num, i);
if (!numsFirstIndex.containsKey(num)) numsFirstIndex.put(num, i);
}
int maxCnt = 0;
for (int num :nums) {
maxCnt = Math.max(maxCnt, numsCnt.get(num));
}
int res = nums.length;
for (int num :nums) {
int cnt = numsCnt.get(num);
if (cnt != maxCnt) continue;
res = Math.min(res, numsLastIndex.get(num) - numsFirstIndex.get(num) + 1);
}
return res;
}
}
Leetcode-766. 托普利茨矩阵
如果一个矩阵的每一方向由左上到右下的对角线上具有相同元素,那么这个矩阵是托普利茨矩阵。
给定一个 M x N 的矩阵,当且仅当它是托普利茨矩阵时返回 True。
示例 1:
输入:
matrix = [
[1,2,3,4],
[5,1,2,3],
[9,5,1,2]
]
输出: True
解释:
在上述矩阵中, 其对角线为:
"[9]", "[5, 5]", "[1, 1, 1]", "[2, 2, 2]", "[3, 3]", "[4]"。
各条对角线上的所有元素均相同, 因此答案是True。
示例 2:
输入:
matrix = [
[1,2],
[2,2]
]
输出: False
解释:
对角线"[1, 2]"上的元素不同。
说明:
- matrix 是一个包含整数的二维数组。
- matrix 的行数和列数均在 [1, 20]范围内。
- matrix[i][j] 包含的整数在 [0, 99]范围内。
进阶:
- 如果矩阵存储在磁盘上,并且磁盘内存是有限的,因此一次最多只能将一行矩阵加载到内存中,该怎么办?
- 如果矩阵太大以至于只能一次将部分行加载到内存中,该怎么办?
解法:
- Java
class Solution {
public boolean isToeplitzMatrix(int[][] matrix) {
for (int j=0;j<matrix[0].length;j++){
if (!check(matrix, 0, j, matrix[0][j])) return false;
}
for (int i=1;i<matrix.length;i++) {
if (!check(matrix, i, 0, matrix[i][0])) return false;
}
return true;
}
private boolean check(int[][] matrix, int i, int j, int expectValue) {
if (i>=matrix.length || j>=matrix[0].length) return true;
if (matrix[i][j]!=expectValue) return false;
return check(matrix, i+1, j+1, expectValue);
}
}
Leetcode-565. 数组嵌套
索引从0开始长度为N的数组A,包含0到N - 1的所有整数。找到并返回最大的集合S,S[i] = {A[i], A[A[i]], A[A[A[i]]], … }且遵守以下的规则。
假设选择索引为i的元素A[i]为S的第一个元素,S的下一个元素应该是A[A[i]],之后是A[A[A[i]]]… 以此类推,不断添加直到S出现重复的元素。
示例 1:
输入: 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}
注意:
- N是[1, 20,000]之间的整数。
- A中不含有重复的元素。
- A中的元素大小在[0, N-1]之间。
解法:
- Java
class Solution {
public int arrayNesting(int[] nums) {
int max = 0;
for (int i=0;i<nums.length;i++) {
int cnt = 0;
for (int j=i;nums[j]!=-1;) {
cnt++;
int tmp = nums[j];
nums[j] = -1;
j = tmp;
}
max = Math.max(max, cnt);
}
return max;
}
}
Leetcode-769. 最多能完成排序的块
数组arr是[0, 1, …, arr.length - 1]的一种排列,我们将这个数组分割成几个“块”,并将这些块分别进行排序。之后再连接起来,使得连接的结果和按升序排序后的原数组相同。
我们最多能将数组分成多少块?
示例 1:
输入: arr = [4,3,2,1,0]
输出: 1
解释:
将数组分成2块或者更多块,都无法得到所需的结果。
例如,分成 [4, 3], [2, 1, 0] 的结果是 [3, 4, 0, 1, 2],这不是有序的数组。
示例 2:
输入: arr = [1,0,2,3,4]
输出: 4
解释:
我们可以把它分成两块,例如 [1, 0], [2, 3, 4]。
然而,分成 [1, 0], [2], [3], [4] 可以得到最多的块数。
注意:
- arr 的长度在 [1, 10] 之间。
- arr[i]是 [0, 1, …, arr.length - 1]的一种排列。
解法:
首先找到从左块开始最小块的大小。如果前 k 个元素为 [0, 1, …, k-1],可以直接把他们分为一个块。当我们需要检查 [0, 1, …, n-1] 中前 k+1 个元素是不是 [0, 1, …, k] 的时候,只需要检查其中最大的数是不是 k 就可以了。
- Java
class Solution {
public int maxChunksToSorted(int[] arr) {
if (arr==null) return 0;
int right = 0, res = 0;
for (int i=0;i<arr.length;i++) {
right = Math.max(right, arr[i]);
if (right==i) res++;
}
return res;
}
}