Leetcode刷题 2021.02.05
Leetcode1267 统计参与通信的服务器
这里有一幅服务器分布图,服务器的位置标识在 m * n 的整数矩阵网格 grid 中,1 表示单元格上有服务器,0 表示没有。
如果两台服务器位于同一行或者同一列,我们就认为它们之间可以进行通信。
请你统计并返回能够与至少一台其他服务器进行通信的服务器的数量。
一开始觉得要用并查集或者DFS,BFS之类的。后来想了一下两次遍历就行了。
class Solution {
public int countServers(int[][] grid) {
int res = 0, m = grid.length, n = grid[0].length;
//设置两个辅助数组,分别判断哪一行或者哪一列有服务器
int[] row = new int[m];
int[] col = new int[n];
for(int i = 0; i < m; i++){
for(int j = 0; j < n; j++){
if (grid[i][j] == 1){
row[i]++;
col[j]++;
}
}
}
for(int i = 0; i < m; i++){
for(int j = 0; j < n; j++){
//第二次遍历,如果该位置是服务器,而且该行或者该列上的服务器数量大于1,就加一次计数
if (grid[i][j] == 1 && (row[i] > 1 || col[j] > 1)){
res++;
}
}
}
return res;
}
}
Leetcode1415 长度为 n 的开心字符串中字典序第 k 小的字符串
一个 「开心字符串」定义为:
仅包含小写字母 [‘a’, ‘b’, ‘c’].
对所有在 1 到 s.length - 1 之间的 i ,满足 s[i] != s[i + 1] (字符串的下标从 1 开始)。
比方说,字符串 “abc”,“ac”,“b” 和 “abcbabcbcb” 都是开心字符串,但是 “aa”,“baa” 和 “ababbc” 都不是开心字符串。
给你两个整数 n 和 k ,你需要将长度为 n 的所有开心字符串按字典序排序。
请你返回排序后的第 k 个开心字符串,如果长度为 n 的开心字符串少于 k 个,那么请你返回 空字符串 。
其实是比较简单的递归题,再纸上画一下树就知道该怎么做了。就是这个代码写的太难看了,还没优化,就先这样吧。
class Solution {
char[] arr = new char[]{'a', 'b', 'c'};
public String getHappyString(int n, int k) {
int num = (int)Math.pow(2, n - 1);
StringBuilder sb = new StringBuilder();
//一开始先处理三个元素的,因为后面的元素不能与前一个相同,所以后面的元素都是只有两种可能性的
if (k <= num){
sb.append('a');
helper(n, k, 0, sb, 1);
}else if (k > num && k <= 2 * num){
sb.append('b');
helper(n, k - num, 1, sb, 1);
}else if (k > 2 * num && k <= 3 * num){
sb.append('c');
helper(n, k - 2 * num, 2, sb, 1);
//如果大于num,就没有结果,返回一个空字符串
}else{
sb.append("");
}
return sb.toString();
}
private void helper(int n, int k, int index, StringBuilder sb, int count){
if (count == n) return;
//看下还有多少个,如果大于前一半选择一个字符递归,后一半选择另一个和字符
int num = (int)Math.pow(2, n - count);
if (k <= num / 2){
int idx = index != 1 ? (index + 1) % 3 : 0;
sb.append(arr[idx]);
helper(n, k, idx, sb, count + 1);
}else{
int idx = index != 1 ? (index + 2) % 3 : 2;
sb.append(arr[idx]);
helper(n, k - num / 2, idx, sb, count + 1);
}
}
}
Leetcode1186 删除一次得到子数组最大和
给你一个整数数组,返回它的某个 非空 子数组(连续元素)在执行一次可选的删除操作后,所能得到的最大元素总和。
换句话说,你可以从原数组中选出一个子数组,并可以决定要不要从中删除一个元素(只能删一次哦),(删除后)子数组中至少应当有一个元素,然后该子数组(剩下)的元素总和是所有子数组之中最大的。
注意,删除一个元素后,子数组 不能为空。
因为要删除一个元素,而要删除哪个元素是不能提前知道的,所以要记下来,因此想到用dp解决。对于一个元素只有删除它或者保留它两种情况。因此dp[i][0]表示以第i个元素结尾的元素不删除元素的情况的最大值,dpi表示示以第i个元素结尾的删除一个元素的情况的最大值。
那么可以得到状态转移方程如果dp[i - 1][0] < 0,那就不要前面的了,因为小于0的话会有副作用,相当于求连续子数组的最大值了。
而dpi - 1 = Math.max(dp[i - 1][0], dpi - 1 + arr[i]),这里表示删除自己,和删除前面的一个元素的最大值。
class Solution {
public int maximumSum(int[] arr) {
int n = arr.length;
int[] dp = new int[2];
dp[0] = arr[0];
dp[1] = arr[0];
int res = arr[0];
for(int i = 1; i < n; i++){
//解释基本都在上面了,这里优化成O(1),要用temp保存下第一个元素,因为第一步可能会更新它
int temp = dp[0];
dp[0] = dp[0] < 0 ? arr[i] : dp[0] + arr[i];
dp[1] = Math.max(temp, dp[1] + arr[i]);
res = Math.max(res, Math.max(dp[0], dp[1]));
}
return res;
}
}