「这是我参与2022首次更文挑战的第32天,活动详情查看:2022首次更文挑战」。
LeetCode习题集 有些题可能直接略过了,整理一下之前刷leetcode
861. 翻转矩阵后的得分
有一个二维矩阵 A 其中每个元素的值为 0 或 1 。
移动是指选择任一行或列,并转换该行或列中的每一个值:将所有 0 都更改为 1,将所有 1 都更改为 0。
在做出任意次数的移动后,将该矩阵的每一行都按照二进制数来解释,矩阵的得分就是这些数字的总和。
返回尽可能高的分数。
示例:
输入: [[0,0,1,1],[1,0,1,0],[1,1,0,0]]
输出: 39
解释: 转换为 [[1,1,1,1],[1,0,0,1],[1,1,1,1]]
0b1111 + 0b1001 + 0b1111 = 15 + 9 + 15 = 39
提示:
1 <= A.length <= 201 <= A[0].length <= 20A[i][j]是0或1
PS:
先初始化,未反转的情况
然后每一行,除了第一列,其他的都加上反转的
然后看看是反转的多还是为反转的多
如果当前行的最左面的1变为二进制的最大数
class Solution {
public int matrixScore(int[][] grid) {
int m = grid.length, n = grid[0].length;
int ret = m * (1 << (n - 1));
for (int j = 1; j < n; j++) {
int nOnes = 0;
for (int i = 0; i < m; i++) {
if (grid[i][0] == 1) {
nOnes += grid[i][j];
} else {
nOnes += (1 - grid[i][j]); // 如果这一行进行了行反转,则该元素的实际取值为 1 - grid[i][j]
}
}
int k = Math.max(nOnes, m - nOnes);
ret += k * (1 << (n - j - 1));
}
return ret;
}
}
863. 二叉树中所有距离为 K 的结点
给定一个二叉树(具有根结点 root), 一个目标结点 target ,和一个整数值 k 。
返回到目标结点 target 距离为 k 的所有结点的值的列表。 答案可以以 任何顺序 返回。
示例 1:
输入: root = [3,5,1,6,2,0,8,null,null,7,4], target = 5, k = 2
输出: [7,4,1]
解释: 所求结点为与目标结点(值为 5)距离为 2 的结点,值分别为 7,4,以及 1
示例 2:
输入: root = [1], target = 1, k = 3
输出: []
提示:
- 节点数在
[1, 500]范围内 0 <= Node.val <= 500Node.val中所有值 不同- 目标结点
target是树上的结点。 0 <= k <= 1000
class Solution {
Map<Integer, TreeNode> parents = new HashMap<Integer, TreeNode>();
List<Integer> ans = new ArrayList<Integer>();
public List<Integer> distanceK(TreeNode root, TreeNode target, int k) {
// 从 root 出发 DFS,记录每个结点的父结点
findParents(root);
// 从 target 出发 DFS,寻找所有深度为 k 的结点
findAns(target, null, 0, k);
return ans;
}
//当前结点的左结点不为空就调用左节点
//右结点不为空则调用右结点
public void findParents(TreeNode node) {
if (node.left != null) {
parents.put(node.left.val, node);
findParents(node.left);
}
if (node.right != null) {
parents.put(node.right.val, node);
findParents(node.right);
}
}
//如果距离为k了直接返回,如果不为k则有左结点就走左结点,有右结点就走有结点
public void findAns(TreeNode node, TreeNode from, int depth, int k) {
if (node == null) {
return;
}
if (depth == k) {
ans.add(node.val);
return;
}
if (node.left != from) {
findAns(node.left, node, depth + 1, k);
}
if (node.right != from) {
findAns(node.right, node, depth + 1, k);
}
if (parents.get(node.val) != from) {
findAns(parents.get(node.val), node, depth + 1, k);
}
}
}
865. 具有所有最深节点的最小子树
给定一个根为 root 的二叉树,每个节点的深度是 该节点到根的最短距离 。
返回包含原始树中所有 最深节点 的 最小子树 。
如果一个节点在 整个树 的任意节点之间具有最大的深度,则该节点是 最深的 。
一个节点的 子树 是该节点加上它的所有后代的集合。
示例 1:
输入: root = [3,5,1,6,2,0,8,null,null,7,4]
输出: [2,7,4]
解释:
我们返回值为 2 的节点,在图中用黄色标记。
在图中用蓝色标记的是树的最深的节点。
注意,节点 5、3 和 2 包含树中最深的节点,但节点 2 的子树最小,因此我们返回它。
示例 2:
输入: root = [1]
输出: [1]
解释: 根节点是树中最深的节点。
示例 3:
输入: root = [0,1,3,null,2]
输出: [2]
解释: 树中最深的节点为 2 ,有效子树为节点 2、1 和 0 的子树,但节点 2 的子树最小。
提示:
- 树中节点的数量在
[1, 500]范围内。 0 <= Node.val <= 500- 每个节点的值都是 独一无二 的。
PS:
遍历的时候,map存储结点和深度
因为本题返回的是最大深度的子树
递归的时候,遍历到每一个结点,同时标记结点的深度
然后把所有深度找出最深的
然后在找到此深度的数组
class Solution {
Map<TreeNode, Integer> depth;
int max_depth;
public TreeNode subtreeWithAllDeepest(TreeNode root) {
depth = new HashMap();
depth.put(null, -1);
dfs(root, null);
max_depth = -1;
for (Integer d: depth.values())
max_depth = Math.max(max_depth, d);
return answer(root);
}
public void dfs(TreeNode node, TreeNode parent) {
if (node != null) {
depth.put(node, depth.get(parent) + 1);
dfs(node.left, node);
dfs(node.right, node);
}
}
public TreeNode answer(TreeNode node) {
if (node == null || depth.get(node) == max_depth)
return node;
TreeNode L = answer(node.left),
R = answer(node.right);
if (L != null && R != null) return node;
if (L != null) return L;
if (R != null) return R;
return null;
}
}
866. 回文素数
求出大于或等于 N 的最小回文素数。
回顾一下,如果一个数大于 1,且其因数只有 1 和它自身,那么这个数是素数。
例如,2,3,5,7,11 以及 13 是素数。
回顾一下,如果一个数从左往右读与从右往左读是一样的,那么这个数是回文数。
例如,12321 是回文数。
示例 1:
输入: 6
输出: 7
示例 2:
输入: 8
输出: 11
示例 3:
输入: 13
输出: 101
提示:
1 <= N <= 10^8- 答案肯定存在,且小于
2 * 10^8。
class Solution {
public int primePalindrome(int N) {
//因为这里是N小于10的8次方,我们一半的只要是小于等于10的五次方就可以,然后在做回文
for (int L = 1; L <= 5; ++L) {
//奇数回文
for (int root = (int)Math.pow(10, L - 1); root < (int)Math.pow(10, L); ++root) {
StringBuilder sb = new StringBuilder(Integer.toString(root));
for (int k = L-2; k >= 0; --k) //这里是已经添加进回文的中间字符
sb.append(sb.charAt(k));
int x = Integer.valueOf(sb.toString());
if (x >= N && isPrime(x))
return x;
//如果没有找到偶数的回文
//return N <= 11 ? min(x, 11) : x
}
//偶数回文
for (int root = (int)Math.pow(10, L - 1); root < (int)Math.pow(10, L); ++root) {
StringBuilder sb = new StringBuilder(Integer.toString(root));
for (int k = L-1; k >= 0; --k) //这里直接循环添加k就可以了
sb.append(sb.charAt(k));
int x = Integer.valueOf(sb.toString());
if (x >= N && isPrime(x))
return x;
}
}
throw null;
}
//检测是否是质数
public boolean isPrime(int N) {
if (N < 2) return false;
int R = (int) Math.sqrt(N);
for (int d = 2; d <= R; ++d)
if (N % d == 0) return false;
return true;
}
}
867. 转置矩阵
给你一个二维整数数组 matrix, 返回 matrix 的 转置矩阵 。
矩阵的 转置 是指将矩阵的主对角线翻转,交换矩阵的行索引与列索引。
示例 1:
输入: matrix = [[1,2,3],[4,5,6],[7,8,9]]
输出: [[1,4,7],[2,5,8],[3,6,9]]
示例 2:
输入: matrix = [[1,2,3],[4,5,6]]
输出: [[1,4],[2,5],[3,6]]
提示:
m == matrix.lengthn == matrix[i].length1 <= m, n <= 10001 <= m * n <= 105-109 <= matrix[i][j] <= 109
PS:
转置矩阵只需要交换矩阵的x,y坐标即可
class Solution {
public int[][] transpose(int[][] matrix) {
int m = matrix.length, n = matrix[0].length;
int[][] transposed = new int[n][m];
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
transposed[j][i] = matrix[i][j];
}
}
return transposed;
}
}
868. 二进制间距
给定一个正整数 n,找到并返回 n 的二进制表示中两个 相邻 1 之间的 最长距离 。如果不存在两个相邻的 1,返回 0 。
如果只有 0 将两个 1 分隔开(可能不存在 0 ),则认为这两个 1 彼此 相邻 。两个 1 之间的距离是它们的二进制表示中位置的绝对差。例如,"1001" 中的两个 1 的距离为 3 。
示例 1:
输入: n = 22
输出: 2
解释: 22 的二进制是 "10110" 。
在 22 的二进制表示中,有三个 1,组成两对相邻的 1 。
第一对相邻的 1 中,两个 1 之间的距离为 2 。
第二对相邻的 1 中,两个 1 之间的距离为 1 。
答案取两个距离之中最大的,也就是 2 。
示例 2:
输入: n = 8
输出: 0
解释: 8 的二进制是 "1000" 。
在 8 的二进制表示中没有相邻的两个 1,所以返回 0 。
示例 3:
输入: n = 5
输出: 2
解释: 5 的二进制是 "101" 。
提示:
1 <= n <= 109
PS:
我们把整数进行二进制化
每次都取二进制的一位,从最后面开始向左一位一位的取
找到最大的两个二进制中1 的距离
class Solution {
public int binaryGap(int N) {
int[] A = new int[32];
int t = 0;
for (int i = 0; i < 32; ++i)
if (((N >> i) & 1) != 0)
A[t++] = i;
int ans = 0;
for (int i = 0; i < t - 1; ++i)
ans = Math.max(ans, A[i+1] - A[i]);
return ans;
}
}
869. 重新排序得到 2 的幂
给定正整数 n ,我们按任何顺序(包括原始顺序)将数字重新排序,注意其前导数字不能为零。
如果我们可以通过上述方式得到 2 的幂,返回 true;否则,返回 false。
示例 1:
输入: n = 1
输出: true
示例 2:
输入: n = 10
输出: false
提示:
1 <= n <= 109
PS:
我们把int转成String,然后换算成字符串
然后进行全排列操作,(循环递归每一位,如果当前位用了,标记一下,然后递归调用,等下一次排列再把这个标记取消,取循环下一个位置)
这里要注意第一位不能为0
每次全排列位数够了以后,进行一次判断,看是否为2的幂
class Solution {
boolean[] vis;
public boolean reorderedPowerOf2(int n) {
char[] nums = Integer.toString(n).toCharArray();
Arrays.sort(nums);
vis = new boolean[nums.length];
return backtrack(nums, 0, 0);
}
public boolean backtrack(char[] nums, int idx, int num) {
if (idx == nums.length) {
return isPowerOfTwo(num);
}
for (int i = 0; i < nums.length; ++i) {
// 不能有前导零
if ((num == 0 && nums[i] == '0') || vis[i] || (i > 0 && !vis[i - 1] && nums[i] == nums[i - 1])) {
continue;
}
vis[i] = true;
if (backtrack(nums, idx + 1, num * 10 + nums[i] - '0')) {
return true;
}
vis[i] = false;
}
return false;
}
public boolean isPowerOfTwo(int n) {
return (n & (n - 1)) == 0;
}
}
870. 优势洗牌
给定两个大小相等的数组 A 和 B,A 相对于 B 的优势可以用满足 A[i] > B[i] 的索引 i 的数目来描述。
返回 A 的任意排列,使其相对于 B 的优势最大化。
示例 1:
输入: A = [2,7,11,15], B = [1,10,4,11]
输出: [2,11,7,15]
示例 2:
输入: A = [12,24,8,32], B = [13,25,32,11]
输出: [24,32,8,12]
提示:
1 <= A.length = B.length <= 100000 <= A[i] <= 10^90 <= B[i] <= 10^9
class Solution {
public int[] advantageCount(int[] A, int[] B) {
int[] sortedA = A.clone();
Arrays.sort(sortedA);
int[] sortedB = B.clone();
Arrays.sort(sortedB);
// assigned[b] b的分配
Map<Integer, Deque<Integer>> assigned = new HashMap();
for (int b: B) assigned.put(b, new LinkedList());
// remaining 不是b的分配
Deque<Integer> remaining = new LinkedList();
//
// sortedB[j] b里面剩余的,把符合利益的和剩余的分开
int j = 0;
for (int a: sortedA) {
if (a > sortedB[j]) {
assigned.get(sortedB[j++]).add(a);
} else {
remaining.add(a);
}
}
// 对分配的和剩余的进行操作
int[] ans = new int[B.length];
for (int i = 0; i < B.length; ++i) {
// 符合分配就把分配的b里面的弹出
if (assigned.get(B[i]).size() > 0)
ans[i] = assigned.get(B[i]).pop();
else //弹出剩余的
ans[i] = remaining.pop();
}
return ans;
}
}