5452. 判断能否形成等差数列
给你一个数字数组 arr 。
如果一个数列中,任意相邻两项的差总等于同一个常数,那么这个数列就称为 等差数列 。
如果可以重新排列数组形成等差数列,请返回 true ;否则,返回 false 。
示例 1:
输入:arr = [3,5,1]
输出:true
解释:对数组重新排序得到 [1,3,5] 或者 [5,3,1] ,任意相邻两项的差分别为 2 或 -2 ,可以形成等差数列。
示例 2:
输入:arr = [1,2,4]
输出:false
解释:无法通过重新排序得到等差数列。
提示:
2 <= arr.length <= 1000
-10^6 <= arr[i] <= 10^6
思路
先排序,再计算两两元素之差。时间复杂度O(n)
代码
class Solution {
public boolean canMakeArithmeticProgression(int[] arr) {
Arrays.sort(arr);
int n = arr.length, i = 0, diff = arr[1] - arr[0];
for (i=2; i<n; ++i) {
if (arr[i] - arr[i-1] != diff) {
return false;
}
}
return true;
}
}
5453. 所有蚂蚁掉下来前的最后一刻
题目难度Medium
有一块木板,长度为 n 个 单位 。一些蚂蚁在木板上移动,每只蚂蚁都以 每秒一个单位 的速度移动。其中,一部分蚂蚁向 左 移动,其他蚂蚁向 右 移动。
当两只向 不同 方向移动的蚂蚁在某个点相遇时,它们会同时改变移动方向并继续移动。假设更改方向不会花费任何额外时间。
而当蚂蚁在某一时刻 t 到达木板的一端时,它立即从木板上掉下来。
给你一个整数 n 和两个整数数组 left 以及 right 。两个数组分别标识向左或者向右移动的蚂蚁在 t = 0 时的位置。请你返回最后一只蚂蚁从木板上掉下来的时刻。
示例 1:
输入:n = 4, left = [4,3], right = [0,1]
输出:4
解释:如上图所示:
-下标 0 处的蚂蚁命名为 A 并向右移动。
-下标 1 处的蚂蚁命名为 B 并向右移动。
-下标 3 处的蚂蚁命名为 C 并向左移动。
-下标 4 处的蚂蚁命名为 D 并向左移动。
请注意,蚂蚁在木板上的最后时刻是 t = 4 秒,之后蚂蚁立即从木板上掉下来。(也就是说在 t = 4.0000000001 时,木板上没有蚂蚁)。
示例 2:
输入:n = 7, left = [], right = [0,1,2,3,4,5,6,7]
输出:7
解释:所有蚂蚁都向右移动,下标为 0 的蚂蚁需要 7 秒才能从木板上掉落。
示例 3:
输入:n = 7, left = [0,1,2,3,4,5,6,7], right = []
输出:7
解释:所有蚂蚁都向左移动,下标为 7 的蚂蚁需要 7 秒才能从木板上掉落。
示例 4:
输入:n = 9, left = [5], right = [4]
输出:5
解释:t = 1 秒时,两只蚂蚁将回到初始位置,但移动方向与之前相反。
示例 5:
输入:n = 6, left = [6], right = [0]
输出:6
提示:
1 <= n <= 10^4
0 <= left.length <= n + 1
0 <= left[i] <= n
0 <= right.length <= n + 1
0 <= right[i] <= n
1 <= left.length + right.length <= n + 1
left 和 right 中的所有值都是唯一的,并且每个值 只能出现在二者之一 中。
思路
可以证明,无论中间有多少蚂蚁,最左边的向右走的蚂蚁和最右边的向左走的蚂蚁走的路是恒定的。时间复杂度O(n)
代码
class Solution {
public int getLastMoment(int n, int[] left, int[] right) {
int rightMostInLeft = -1, leftMostInRight = n + 1;
for (int l: left) {
rightMostInLeft = Math.max(l, rightMostInLeft);
}
for (int r: right) {
leftMostInRight = Math.min(r, leftMostInRight);
}
if (rightMostInLeft == -1) {
return n - leftMostInRight;
}
if (leftMostInRight == n + 1) {
return rightMostInLeft;
}
return Math.max(n - leftMostInRight, rightMostInLeft);
}
}
5454. 统计全 1 子矩形
题目难度Medium
给你一个只包含 0 和 1 的 rows * columns 矩阵 mat ,请你返回有多少个 子矩形 的元素全部都是 1 。
示例 1:
输入:mat = [[1,0,1],
[1,1,0],
[1,1,0]]
输出:13
解释:
有 6 个 1x1 的矩形。
有 2 个 1x2 的矩形。
有 3 个 2x1 的矩形。
有 1 个 2x2 的矩形。
有 1 个 3x1 的矩形。
矩形数目总共 = 6 + 2 + 3 + 1 + 1 = 13 。
示例 2:
输入:mat = [[0,1,1,0],
[0,1,1,1],
[1,1,1,0]]
输出:24
解释:
有 8 个 1x1 的子矩形。
有 5 个 1x2 的子矩形。
有 2 个 1x3 的子矩形。
有 4 个 2x1 的子矩形。
有 2 个 2x2 的子矩形。
有 2 个 3x1 的子矩形。
有 1 个 3x2 的子矩形。
矩形数目总共 = 8 + 5 + 2 + 4 + 2 + 2 + 1 = 24 。
示例 3:
输入:mat = [[1,1,1,1,1,1]]
输出:21
示例 4:
输入:mat = [[1,0,1],[0,1,0],[1,0,1]]
输出:5
提示:
1 <= rows <= 150
1 <= columns <= 150
0 <= mat[i][j] <= 1
思路
用前缀和计算(0, 0)到(i, j)之间矩形区域mat值之和。将判断全1矩形转化为计算矩形区域的mat值是否等于矩形区域的面积,其中矩形区域的mat值用前缀和计算。时间复杂度O(n^2 * m^2)
.
代码
class Solution {
public int numSubmat(int[][] mat) {
int m = mat.length, n = mat[0].length;
int[][] corner = new int[m+1][n+1];
int i = 0, j = 0, k = 0, l = 0, ans = 0;
for (i=1; i<=m; ++i) {
for (j=1; j<=n; ++j) {
corner[i][j] = corner[i-1][j] + corner[i][j-1] - corner[i-1][j-1] + mat[i-1][j-1];
}
}
for (i=0; i<m; ++i) {
for (j=0; j<n; ++j) {
for (k=i+1; k<=m; ++k) {
for (l=j+1; l<=n; ++l) {
if (corner[k][l] - corner[i][l] - corner[k][j] + corner[i][j] == (k-i) * (l - j)) {
// System.out.println(i + " " + j + " " + k + " " + l);
++ans;
}
}
}
}
}
return ans;
}
}
5455. 最多 K 次交换相邻数位后得到的最小整数
题目难度Hard
给你一个字符串 num 和一个整数 k 。其中,num 表示一个很大的整数,字符串中的每个字符依次对应整数上的各个 数位 。
你可以交换这个整数相邻数位的数字 最多 k 次。
请你返回你能得到的最小整数,并以字符串形式返回。
示例 1:
输入:num = “4321”, k = 4
输出:“1342”
解释:4321 通过 4 次交换相邻数位得到最小整数的步骤如上图所示。
示例 2:
输入:num = “100”, k = 1
输出:“010”
解释:输出可以包含前导 0 ,但输入保证不会有前导 0 。
示例 3:
输入:num = “36789”, k = 1000
输出:“36789”
解释:不需要做任何交换。
示例 4:
输入:num = “22”, k = 22
输出:“22”
示例 5:
输入:num = “9438957234785635408”, k = 23
输出:“0345989723478563548”
提示:
1 <= num.length <= 30000
num 只包含 数字 且不含有 前导 0 。
1 <= k <= 10^9
思路
贪心。从首位置开始考虑每一个位置,每次找到该位置之后k个元素之内最小的元素,通个与前面的元素进行两两交换,把这个最小元素交换到当前位置,并维护k的值,减去已经用掉的交换次数。直到所有的交换次数用尽。
代码
class Solution {
private String swap(String str, int i, int j) {
return str.substring(0, i) + str.charAt(j) + str.substring(i+1, j) + str.charAt(i) + str.substring(j+1);
}
private int findMin(String str, int left, int range) {
char curMin = str.charAt(left);
int minIdx = left;
for (int i=1; i<=range; ++i) {
if (str.charAt(left + i) < curMin) {
curMin = str.charAt(left + i);
minIdx = left + i;
}
}
return minIdx;
}
public String minInteger(String num, int k) {
int left = 0, n = num.length();
while (k > 0 && left < n) {
int range = Math.min(k, n - 1 - left);
int minIdx = findMin(num, left, range);
if (minIdx != left) {
num = num.substring(0, left) + num.charAt(minIdx) + num.substring(left, minIdx) + num.substring(minIdx + 1);
}
k -= minIdx - left;
++left;
}
return num;
}
}