# LeetCode 6
2021.11 ~
- 575. 分糖果
- 409. 最长回文串
- 918. 环形子数组的最大和
- 452. 用最少数量的箭引爆气球
- 407. 接雨水 II
- 1094. 拼车
- 1427. 字符串的左右移
- 367. 有效的完全平方数
- 1567. 乘积为正数的最长子数组长度
- 44. 通配符匹配
- 598. 范围求和 II
- 281. 锯齿迭代器
- 299. 猜数字游戏
- 394. 字符串解码
- 488. 祖玛游戏
- 495. 提莫攻击
- 402. 移掉 K 位数字
- 1469. 寻找所有的独生节点
- 1602. 找到二叉树中最近的右侧节点
- 629. K个逆序对数组
- 862. 和至少为 K 的最短子数组
- 214. 最短回文串
- 375. 猜数字大小 II
- 1522. N 叉树的直径
- 520. 检测大写字母
- 366. 寻找二叉树的叶子节点
- 1325. 删除给定值的叶子节点
- 677. 键值映射
- 319. 灯泡开关
- 886. 可能的二分法
- 391. 完美矩形
- 261. 以图判树
- 124. 二叉树中的最大路径和
- 968. 监控二叉树
- 318. 最大单词长度乘积
- 990. 等式方程的可满足性
- 1319. 连通网络的操作次数
- 563. 二叉树的坡度
- 305. 岛屿数量 II
- 1579. 保证图可完全遍历
- 1314. 矩阵区域和
- 397. 整数替换
- 323. 无向图中连通分量的数目
- 1101. 彼此熟识的最早时间
- 1227. 飞机座位分配概率
- 594. 最长和谐子序列
- 559. N 叉树的最大深度
- 253. 会议室 II
- 767. 重构字符串
- 859. 亲密字符串
- 358. K 距离间隔重排字符串
- 423. 从英文中重建数字
- 700. 二叉搜索树中的搜索
- 519. 随机翻转矩阵
- 593. 有效的正方形
- 786. 第 K 个最小的素数分数
- 400. 第 N 位数字
- 1446. 连续字符
- 759. 员工空闲时间
- 729. 我的日程安排表 I
- 506. 相对名次
- 1606. 找到处理最多请求的服务器
- 1005. K 次取反后最大化的数组和
- 336. 回文对
- 1858. 包含所有前缀的最长单词
- 372. 超级次方
- 1816. 截断句子
- 1034. 边界着色
- 1756. 设计最近使用(MRU)队列
- 689. 三个无重叠子数组的最大和
- 794. 有效的井字游戏
- 709. 转换成小写字母
- 642. 设计搜索自动补全系统
- 807. 保持城市天际线
- 630. 课程表 III
- 851. 喧闹和富有
- 997. 找到小镇的法官
- 1518. 换酒问题
- 475. 供暖器
- 1154. 一年中的第几天
- 686. 重复叠加字符串匹配
- 1044. 最长重复子串
- 1705. 吃苹果的最大数目
- 1609. 奇偶树
- 1078. Bigram 分词
- 825. 适龄的朋友
- 472. 连接词
- 1995. 统计特殊四元组
- 846. 一手顺子
- 1296. 划分数组为连续数字的集合
- 507. 完美数
# 575. 分糖果
class Solution {
public int distributeCandies(int[] candyType) {
Set<Integer> set = new HashSet<>(candyType.length);
int cnt = 0, n = candyType.length;
for (int i : candyType) {
if (set.add(i)) {
cnt++;
}
}
return cnt >= (n/2) ? (n/2) : cnt;
}
}
# 409. 最长回文串
class Solution {
public int longestPalindrome(String s) {
int[] map = new int[58];
for (char c : s.toCharArray()) {
map[c-65]++;
}
// System.out.println(Arrays.toString(map));
int cnt = 0;
for (int i : map) {
if (i >= 2) {
cnt += (i/2*2);
}
}
return cnt == s.length() ? cnt : cnt+1;
}
}
# 918. 环形子数组的最大和
暴力枚举,超时:
class Solution {
public int maxSubarraySumCircular(int[] nums) {
int n = nums.length;
int max = nums[0];
for (int i = 0; i < 2*n; i++) {
int ii = i%n;
int cmax = nums[ii];
int csum = nums[ii];
for (int j = i-1; j >= 0 && j > i-n; j--) {
csum += nums[j%n];
cmax = Math.max(cmax, csum);
}
// System.out.println("csum:"+csum+"cmax:"+cmax+"; max:"+max);
max = Math.max(max, cmax);
}
return max;
}
}
class Solution {
public int maxSubarraySumCircular(int[] nums) {
int n = nums.length;
int max = nums[0], maxSum = nums[0];
int min = nums[0], minSum = nums[0];
int singleMax = nums[0];
int sum = nums[0];
for (int i = 1; i < n; i++) {
sum += nums[i];
maxSum = (maxSum < 0 ? nums[i] : maxSum+nums[i]);
max = Math.max(max, maxSum);
minSum = minSum > 0 ? nums[i] : minSum+nums[i];
min = Math.min(min, minSum);
singleMax = Math.max(singleMax, nums[i]);
}
return Math.max(max, sum-min==0?singleMax:sum-min);
}
}
将上述代码的Math方法换成三元表达式,可以提高运行效率
class Solution {
public int maxSubarraySumCircular(int[] nums) {
int n = nums.length;
int max = nums[0], maxSum = nums[0];
int min = nums[0], minSum = nums[0];
int singleMax = nums[0];
int sum = nums[0];
for (int i = 1; i < n; i++) {
sum += nums[i];
maxSum = (maxSum < 0 ? nums[i] : maxSum+nums[i]);
max = max > maxSum ? max : maxSum;
minSum = minSum > 0 ? nums[i] : minSum+nums[i];
min = min < minSum ? min : minSum;
singleMax = singleMax > nums[i] ? singleMax : nums[i];
}
return Math.max(max, sum-min==0?singleMax:sum-min);
}
}
# 452. 用最少数量的箭引爆气球
贪心
class Solution {
public int findMinArrowShots(int[][] points) {
Arrays.sort(points, (a, b) -> {
if (a[1] > b[1]) {
return 1;
} else if (a[1] < b[1]) {
return -1;
} else {
return 0;
}
});
// System.out.println(Arrays.deepToString(points));
int pre = points[0][1];
int cnt = 1;
for (int i = 1; i < points.length; i++) {
if (points[i][0] > pre) {
cnt++;
pre = points[i][1];
}
}
return cnt;
}
}
# 407. 接雨水 II
优先队列
class Solution {
public int trapRainWater(int[][] heightMap) {
int row = heightMap.length;
int col = heightMap[0].length;
boolean[][] visited = new boolean[row][col];
//
PriorityQueue<int[]> pq = new PriorityQueue<int[]>((o1, o2) -> o1[2] - o2[2]);
for (int r = 0; r < row; r++) {
for (int c = 0; c < col; c++) {
if (r == 0 || c == 0 || r == row-1 || c == col-1) {
visited[r][c] = true;
pq.offer(new int[]{r, c, heightMap[r][c]});
}
}
}
// print
// while (!pq.isEmpty()) {
// System.out.println(Arrays.toString(pq.poll()));
// }
int res = 0;
int[] dir = new int[]{-1, 0, 1, 0, -1};
while (!pq.isEmpty()) {
int[] poll = pq.poll();
for (int k = 0; k < 4; k++) {
int nr = poll[0]+dir[k];
int nc = poll[1]+dir[k+1];
if (nr >= 0 && nr < row && nc >= 0 && nc < col && !visited[nr][nc]) {
if (poll[2] > heightMap[nr][nc]) {
res += poll[2]-heightMap[nr][nc];
}
pq.offer(new int[]{nr, nc, Math.max(poll[2], heightMap[nr][nc])});
visited[nr][nc] = true;
}
}
}
return res;
}
}
# 1094. 拼车
# 1427. 字符串的左右移
class Solution {
public String stringShift(String s, int[][] shift) {
int offset = 0;
for (int[] i : shift) {
if (i[0] == 0) {
offset += i[1];
} else {
offset -= i[1];
}
}
offset %= s.length();
if (offset > 0) {
return s.substring(offset) + s.substring(0, offset);
} else {
offset = -offset;
return s.substring(s.length()-offset) + s.substring(0, s.length()-offset);
}
}
}
# 367. 有效的完全平方数
二分
class Solution {
public boolean isPerfectSquare(int num) {
long l = 1, r = (num+1) / 2;
while (l <= r) {
long mid = l+((r-l)>>1);
long multi = mid*mid;
if (multi == num) {
return true;
} else if (multi > num) {
r = mid-1;
} else {
l = mid+1;
}
}
return false;
}
}
# 1567. 乘积为正数的最长子数组长度
动态规划
class Solution {
public int getMaxLen(int[] nums) {
int min = nums[0] < 0 ? 1 : 0, max = nums[0] > 0 ? 1 : 0;
int res = max;
for (int i = 1; i < nums.length; i++) {
if (nums[i] > 0) {
max = max+1;
min = min > 0 ? min+1 : 0;
} else if (nums[i] < 0) {
int cmax = min > 0 ? min+1 : 0;
min = max+1;
max = cmax;
} else {
max = 0;
min = 0;
}
res = Math.max(res, max);
}
return res;
}
}
# 44. 通配符匹配
动态规划
class Solution {
public boolean isMatch(String _s, String _p) {
char[] s = _s.toCharArray();
char[] p = _p.toCharArray();
int sn = s.length;
int pn = p.length;
boolean[][] dp = new boolean[sn+1][pn+1];
// init
dp[0][0] = true;
for (int j = 1; j < pn+1; j++) {
dp[0][j] = p[j-1] == '*' && dp[0][j-1];
}
for (int i = 0; i < sn; i++) {
for (int j = 0; j < pn; j++) {
if (p[j] == '*') {
dp[i+1][j+1] = dp[i+1][j] || dp[i][j+1] || dp[i][j];
} else {
dp[i+1][j+1] = firstMath(s, p, i, j) && dp[i][j];
}
}
}
// System.out.println(Arrays.deepToString(dp));
return dp[sn][pn];
}
private boolean firstMath(char[] s, char[] p, int i, int j) {
return s[i] == p[j] || p[j] == '?';
}
}
# 598. 范围求和 II
class Solution {
public int maxCount(int m, int n, int[][] ops) {
int r = m, c = n;
for (int i = 0; i < ops.length; i++) {
r = Math.min(r, ops[i][0]);
c = Math.min(c, ops[i][1]);
}
return r*c;
}
}
# 281. 锯齿迭代器
队列
public class ZigzagIterator {
Queue<Integer> q = new LinkedList<>();
public ZigzagIterator(List<Integer> v1, List<Integer> v2) {
int n1 = v1.size();
int n2 = v2.size();
int n = Math.max(n1, n2);
for (int i = 0; i < n; i++) {
if (i < v1.size()) {
q.offer(v1.get(i));
}
if (i < v2.size()) {
q.offer(v2.get(i));
}
}
}
public int next() {
return q.poll();
}
public boolean hasNext() {
return !q.isEmpty();
}
}
# 299. 猜数字游戏
class Solution {
public String getHint(String secret, String guess) {
int n = secret.length();
int[] smap = new int[10];
int[] gmap = new int[10];
int x = 0, y = 0;
for (int i = 0; i < n; i++) {
int s = secret.charAt(i)-'0';
int g = guess.charAt(i)-'0';
if (s == g) {
x++;
} else {
smap[s]++;
gmap[g]++;
}
}
for (int i = 0; i < 10; i++) {
y += Math.min(smap[i], gmap[i]);
}
return new StringBuilder().append(x).append('A').append(y).append('B').toString();
}
}
# 394. 字符串解码
利用栈特性
class Solution {
public String decodeString(String s) {
Stack<String[]> stack = new Stack<>();
int i = 0;
int n = s.length();
StringBuilder str = new StringBuilder();
while (i < n) {
while (i < n && !(s.charAt(i) > '0' && s.charAt(i) < '9' || s.charAt(i) == ']')) {
str.append(s.charAt(i));
i++;
}
StringBuilder num = new StringBuilder();
while (i < n && (s.charAt(i) >= '0' && s.charAt(i) <= '9')) {
num.append(s.charAt(i));
i++;
}
while (i < n && s.charAt(i) == ']') {
String[] arr = stack.pop();
StringBuilder pop = new StringBuilder();
pop.append(arr[0]);
for (int k = 0; k < Integer.valueOf(arr[1]); k++) {
pop.append(str);
}
str = pop;
i++;
}
if (i < n && s.charAt(i) == '[') {
stack.push(new String[]{str.toString(), num.toString()});
str = new StringBuilder();
i++;
}
}
return str.toString();
}
}
# 488. 祖玛游戏
dfs+剪枝
class Solution {
int INF = 0x3f3f3f3f;
int m;
String b;
Map<String, Integer> map = new HashMap<>();
public int findMinStep(String board, String hand) {
m = hand.length();
b = hand;
int ans = dfs(board, 1<<m);
return ans == INF ? -1 : ans;
}
private int dfs(String a, int vis) {
int n = a.length();
if (n == 0) return 0;
int ans = INF;
if (map.containsKey(a)) return map.get(a);
for (int i = 0; i < m; i++) {
if (((vis >> i) & 1) == 1) continue;
int next = (vis | (1 << i));
for (int j = 0; j <= n; j++) {
// 剪枝
boolean ok = false;
if (j > 0 && j < n && a.charAt(j) == a.charAt(j-1) && a.charAt(j-1) != b.charAt(i)) ok = true;
if (j < n && a.charAt(j) == b.charAt(i)) ok = true;
if (!ok) continue;
StringBuilder str = new StringBuilder();
str.append(a.substring(0, j)).append(b.substring(i, i+1));
if (j < n) {
str.append(a.substring(j));
}
int k = j;
while (k >= 0 && k < str.length()) {
char c = str.charAt(k);
int l = k, r = k;
while (l >= 0 && str.charAt(l) == c) {
l--;
}
while (r < str.length() && str.charAt(r) == c) {
r++;
}
if (r-1-l >= 3) {
str.delete(l+1, r);
k = l < 0 ? r : l;
} else {
break;
}
}
ans = Math.min(ans, dfs(str.toString(), next)+1);
}
}
map.put(a, ans);
return ans;
}
}
# 495. 提莫攻击
class Solution {
public int findPoisonedDuration(int[] timeSeries, int duration) {
int res = duration;
int pre = timeSeries[0]+duration-1;
for (int i = 1; i < timeSeries.length; i++) {
if (timeSeries[i] <= pre) {
res -= (pre-timeSeries[i]+1);
}
res += duration;
pre = timeSeries[i]+duration-1;
}
return res;
}
}
# 402. 移掉 K 位数字
单调栈
class Solution {
public String removeKdigits(String num, int k) {
LinkedList<Character> q = new LinkedList<>();
for (int i = 0; i < num.length(); i++) {
char cur = num.charAt(i);
while (!q.isEmpty() && k > 0 && q.peekLast() > cur) {
q.pollLast();
k--;
}
q.offer(cur);
}
StringBuilder res = new StringBuilder();
int sz = q.size()-k;
boolean firstZero = true;
for (int i = 0; i < sz; i++) {
char cur = q.pollFirst();
if (firstZero && cur == '0') {
continue;
} else {
firstZero = false;
}
res.append(cur);
}
String ans = res.toString();
return ans.equals("") ? "0" : ans;
}
}
# 1469. 寻找所有的独生节点
class Solution {
List<Integer> res = new ArrayList<>();
public List<Integer> getLonelyNodes(TreeNode root) {
dfs(root);
return res;
}
private void dfs(TreeNode node) {
if (node == null) return;
int l = 0, r = 0;
if (node.left != null) {
l = 1;
dfs(node.left);
}
if (node.right != null) {
r = 1;
dfs(node.right);
}
if ((l^r) == 1) {
if (l == 1) res.add(node.left.val);
if (r == 1) res.add(node.right.val);
}
}
}
# 1602. 找到二叉树中最近的右侧节点
class Solution {
public TreeNode findNearestRightNode(TreeNode root, TreeNode u) {
if (root == null) return null;
Queue<TreeNode> q = new LinkedList<>();
q.offer(root);
while (!q.isEmpty()) {
int sz = q.size();
for (int i = 0; i < sz; i++) {
TreeNode cur = q.poll();
if (cur == u) {
if (i < sz-1) {
return q.peek();
} else {
return null;
}
}
if (cur.left != null) q.offer(cur.left);
if (cur.right != null) q.offer(cur.right);
}
}
return null;
}
}
# 629. K个逆序对数组
没做出来,看了很久多题解才理解如何dp,但是写的时候仍然很困难,显然没有理解到位
class Solution {
int mod = (int)1e9+7;
public int kInversePairs(int n, int k) {
long[][] dp = new long[n+1][k+1];
long[][] pre = new long[n+1][k+1];
dp[1][0] = 1;
Arrays.fill(pre[1], 1);
for (int i = 2; i <= n; i++) {
for (int j = 0; j <= k; j++) {
dp[i][j] = j < i ? pre[i-1][j] : pre[i-1][j] - pre[i-1][j-(i-1)-1];
dp[i][j] = (dp[i][j] + mod) % mod;
pre[i][j] = j == 0 ? dp[i][j] : dp[i][j] + pre[i][j-1];
pre[i][j] = (pre[i][j] + mod) % mod;
}
}
return (int)dp[n][k];
}
}
# 862. 和至少为 K 的最短子数组
前缀后+双端队列
class Solution {
int N = Integer.MAX_VALUE;
public int shortestSubarray(int[] nums, int k) {
int n = nums.length;
long[] pre = new long[n+1];
for (int i = 0; i < n; i++) {
pre[i+1] = pre[i] + nums[i];
}
// System.out.println(Arrays.toString(pre));
int res = N;
Deque<Integer> q = new LinkedList<>();
// q.offer(0);
for (int i = 0; i <= n; i++) {
long cur = pre[i];
if (q.isEmpty()) {
if (cur >= k) {
res = Math.min(res, i+1);
}
} else {
while (!q.isEmpty() && cur <= pre[q.peekLast()]) {
q.pollLast();
}
while (!q.isEmpty() && cur-pre[q.peekFirst()] >= k) {
int poll = q.pollFirst();
res = Math.min(res, i-poll);
}
}
q.offerLast(i);
}
return res == N ? -1 : res;
}
}
# 214. 最短回文串
class Solution {
public String shortestPalindrome(String s) {
int i = 0, n = s.length(), j = n-1;
while (j >= 0) {
if (s.charAt(i) == s.charAt(j)) {
i++;
}
j--;
}
if (i == n) {
return s;
}
String suffix = s.substring(i);
StringBuilder rev = new StringBuilder(suffix).reverse();
return rev.append(shortestPalindrome(s.substring(0, i))+s.substring(i)).toString();
}
}
# 375. 猜数字大小 II
class Solution {
public int getMoneyAmount(int n) {
int[][] dp = new int[n+1][n+1];
int INF = Integer.MAX_VALUE;
for (int j = 2; j <= n; j++) {
for (int i = j-1; i >= 1; i--) {
dp[i][j] = INF;
for (int k = i; k <= j; k++) {
int tmp = Math.max(k==i?0:(dp[i][k-1]+k), k==j?0:(dp[k+1][j]+k));
dp[i][j] = Math.min(dp[i][j], tmp);
// System.out.println("i:"+i+"; j:"+j+"; k:"+k+"; dp:"+dp[i][j]+"; tmp:"+tmp);
}
}
}
return dp[1][n];
}
}
# 1522. N 叉树的直径
class Solution {
int max = 0;
public int diameter(Node root) {
dfs(root);
return max;
}
private int dfs(Node node) {
if (node == null) return 0;
int first = 0, sec = 0;
List<Node> childs = node.children;
for (Node n : childs) {
int res = dfs(n);
if (res > first) {
sec = first;
first = res;
} else if (res <= first && res > sec) {
sec = res;
}
}
max = Math.max(max, first+sec);
return first == 0 ? 1 : (first+1);
}
}
# 520. 检测大写字母
class Solution {
public boolean detectCapitalUse(String word) {
int cnt = 0, up = 0;
for (int i = 0; i < word.length(); i++) {
char c = word.charAt(i);
if (c >= 'A' && c <= 'Z') {
up++;
}
cnt++;
}
return cnt == up || up == 0 || (cnt > 1 && up == 1 && word.charAt(0) >= 'A' && word.charAt(0) <= 'Z');
}
}
# 366. 寻找二叉树的叶子节点
class Solution {
List<List<Integer>> res = new ArrayList<>();
public List<List<Integer>> findLeaves(TreeNode root) {
dfs(root);
return res;
}
private int dfs(TreeNode node) {
if (node == null) return 0;
int l = dfs(node.left);
int r = dfs(node.right);
int level = Math.max(l, r)+1;
List<Integer> list;
if (level-1 >= res.size()) {
list = new ArrayList<>();
res.add(level-1, list);
} else {
list = res.get(level-1);
}
list.add(node.val);
return level;
}
}
# 1325. 删除给定值的叶子节点
class Solution {
int t;
public TreeNode removeLeafNodes(TreeNode root, int target) {
t = target;
boolean res = dfs(root);
if (res) root = null;
return root;
}
private boolean dfs(TreeNode node) {
if (node == null) return true;
boolean l = dfs(node.left);
boolean r = dfs(node.right);
if (l) node.left = null;
if (r) node.right = null;
if (l && r && t == node.val) {
return true;
}
return false;
}
}
# 677. 键值映射
class MapSum {
TrieNode root;
public MapSum() {
root = new TrieNode();
}
public void insert(String key, int val) {
TrieNode p = root;
for (int i = 0; i < key.length(); i++) {
int c = (int) (key.charAt(i)-'a');
if (p.ns[c] == null) {
p.ns[c] = new TrieNode();
}
p = p.ns[c];
}
p.end = true;
p.val = val;
}
public int sum(String prefix) {
TrieNode p = root;
for (int i = 0; i < prefix.length(); i++) {
int c = (int) (prefix.charAt(i)-'a');
if (p.ns[c] == null) {
return 0;
}
p = p.ns[c];
}
return dfs(p);
}
private int dfs(TrieNode node) {
int sum = node.val;
for (TrieNode n : node.ns) {
if (n != null) {
sum += dfs(n);
}
}
return sum;
}
class TrieNode {
boolean end;
TrieNode[] ns = new TrieNode[26];
int val;
}
}
# 319. 灯泡开关
class Solution {
public int bulbSwitch(int n) {
return (int) Math.floor(Math.sqrt(n));
}
}
# 886. 可能的二分法
class Solution {
int[] father;
public boolean possibleBipartition(int n, int[][] dislikes) {
int N = 2*n+1;
father = new int[N];
for (int i = 0; i < N; i++) {
father[i] = i;
}
for (int i = 0; i < dislikes.length; i++) {
int d0 = dislikes[i][0];
int d1 = dislikes[i][1];
int x = find(d0);
int y = find(d1);
int a = find(d0+n);
int b = find(d1+n);
if (x == y) {
return false;
} else {
father[b] = x;
father[a] = y;
}
}
return true;
}
private int find(int x) {
if (father[x] != x) {
father[x] = find(father[x]);
}
return father[x];
}
}
# 391. 完美矩形
class Solution {
public boolean isRectangleCover(int[][] rectangles) {
int area = 0;
int[] left = null, right = null;
Set<Integer> set = new HashSet<>();
for (int[] rec : rectangles) {
area += ((rec[2]-rec[0])*(rec[3]-rec[1]));
if (left == null || rec[0] < left[0] || rec[1] < left[1]) {
left = new int[]{rec[0], rec[1]};
}
if (right == null || rec[2] > right[0] || rec[3] > right[1]) {
right = new int[]{rec[2], rec[3]};
}
int k1 = getKey(rec[0], rec[1]);
int k2 = getKey(rec[0], rec[3]);
int k3 = getKey(rec[2], rec[3]);
int k4 = getKey(rec[2], rec[1]);
if (!set.add(k1)) set.remove(k1);
if (!set.add(k2)) set.remove(k2);
if (!set.add(k3)) set.remove(k3);
if (!set.add(k4)) set.remove(k4);
}
if (area != (right[0]-left[0])*(right[1]-left[1])) {
return false;
}
return set.size() == 4 && set.contains(getKey(left[0], left[1])) && set.contains(getKey(left[0], right[1])) && set.contains(getKey(right[0], right[1])) && set.contains(getKey(right[0], left[1]));
}
private int getKey(int x, int y) {
return x*1000001+y;
}
}
# 261. 以图判树
并查集
class Solution {
public boolean validTree(int n, int[][] edges) {
father = new int[n];
for (int i = 0; i < n; i++) {
father[i] = i;
}
for (int i = 0; i < edges.length; i++) {
int[] c = edges[i];
int x = find(c[0]);
int y = find(c[1]);
if (x == y) {
return false;
} else {
father[x] = y;
}
}
for (int i = 0; i < n; i++) {
find(i);
}
for (int i = 1; i < n; i++) {
if (father[i]!=father[i-1]) {
return false;
}
}
return true;
}
int[] father;
private int find(int x) {
if (x != father[x]) {
father[x] = find(father[x]);
}
return father[x];
}
}
# 124. 二叉树中的最大路径和
class Solution {
int max = Integer.MIN_VALUE;
public int maxPathSum(TreeNode root) {
dfs(root);
return max;
}
private int dfs(TreeNode node) {
if (node == null) return 0;
int left = dfs(node.left);
int right = dfs(node.right);
int res = node.val + Math.max(0, Math.max(left, right));
max = Math.max(max, Math.max(res, left+right+node.val));
return res;
}
}
# 968. 监控二叉树
class Solution {
int cnt = 0;
Boolean ok = true;
Boolean fail = false;
public int minCameraCover(TreeNode root) {
Boolean res = dfs(root);
if (res == fail) cnt++;
return cnt;
}
private Boolean dfs(TreeNode node) {
if (node == null) return null;
Boolean left = dfs(node.left);
Boolean right = dfs(node.right);
if (left == fail || right == fail) {
cnt++;
return true;
}
if (left == ok || right == ok) {
return null;
}
return false;
}
}
# 318. 最大单词长度乘积
同:剑指 Offer II 005. 单词长度的最大乘积
class Solution {
public int maxProduct(String[] words) {
int n = words.length;
int[] mask = new int[n];
for (int i = 0; i < n; i++) {
char[] cs = words[i].toCharArray();
int m = 0;
for (char c : cs) {
m = m | (1 << (c-'a'));
}
mask[i] = m;
}
int max = 0;
for (int i = 0; i < n; i++) {
for (int j = i+1; j < n; j++) {
if ((mask[i] & mask[j]) == 0) {
max = Math.max(max, words[i].length()*words[j].length());
}
}
}
return max;
}
}
# 990. 等式方程的可满足性
并查集
class Solution {
int[] father;
public boolean equationsPossible(String[] equations) {
father = new int[26];
for (int i = 0; i < 26; i++) {
father[i] = i;
}
List<String> notEquals = new ArrayList<>();
for (int i = 0; i < equations.length; i++) {
if (equations[i].charAt(1) == '!') {
notEquals.add(equations[i]);
} else {
int s0 = equations[i].charAt(0)-'a', s3 = equations[i].charAt(3)-'a';
int r0 = find(s0);
int r3 = find(s3);
father[r0] = r3;
}
}
for (String s : notEquals) {
int s0 = s.charAt(0)-'a', s3 = s.charAt(3)-'a';
int r0 = find(s0);
int r3 = find(s3);
if (r0 == r3) return false;
}
return true;
}
private int find(int x) {
if (x != father[x]) {
father[x] = find(father[x]);
}
return father[x];
}
}
# 1319. 连通网络的操作次数
并查集
class Solution {
int[] father;
public int makeConnected(int n, int[][] connections) {
if (connections.length < n-1) return -1;
father = new int[n];
for (int i = 0; i < n; i++) {
father[i] = i;
}
for (int i = 0; i < connections.length; i++) {
int r0 = find(connections[i][0]);
int r1 = find(connections[i][1]);
father[r0] = r1;
}
Set<Integer> set = new HashSet<>();
for (int i = 0; i < n; i++) {
find(i);
set.add(father[i]);
}
return set.size()-1;
}
private int find(int x) {
if (x != father[x]) {
father[x] = find(father[x]);
}
return father[x];
}
}
# 563. 二叉树的坡度
class Solution {
int res = 0;
public int findTilt(TreeNode root) {
dfs(root);
return res;
}
private int dfs(TreeNode node) {
if (node == null) return 0;
int l = dfs(node.left);
int r = dfs(node.right);
res += Math.abs(l-r);
return l + r + node.val;
}
}
# 305. 岛屿数量 II
并查集
class Solution {
int[] father;
int[][] dd = new int[][]{{0, 1},{1, 0},{0, -1},{-1,0}};
int cnt = 0;
public List<Integer> numIslands2(int m, int n, int[][] positions) {
int sz = m*n;
father = new int[sz];
boolean[] grid = new boolean[sz];
List<Integer> res = new ArrayList<>();
for (int i = 0; i < sz; i++) {
father[i] = i;
}
for (int i = 0; i < positions.length; i++) {
// x*n+y
int x = positions[i][0];
int y = positions[i][1];
int pos = x*n+y;
if (!grid[pos]) {
cnt++;
grid[pos] = true;
for (int[] d : dd) {
int newX = x+d[0];
int newY = y+d[1];
int newPos = newX*n+newY;
if (inArea(newX, newY, m, n) && grid[newPos] && !isConnected(pos, newPos)) {
union(pos, newPos);
}
}
}
res.add(cnt);
}
return res;
}
private boolean isConnected(int x, int y) {
return find(x) == find(y);
}
private void union(int x, int y) {
int rx = find(x);
int ry = find(y);
if (rx == ry) {
return;
}
father[rx] = ry;
cnt--;
}
private int find(int x) {
if (x != father[x]) {
father[x] = find(father[x]);
}
return father[x];
}
private boolean inArea(int x, int y, int m, int n) {
return x >= 0 && x < m && y >= 0 && y < n;
}
}
# 1579. 保证图可完全遍历
并查集
class Solution {
public int maxNumEdgesToRemove(int n, int[][] edges) {
UnionSet usa = new UnionSet(n+1);
UnionSet usb = new UnionSet(n+1);
int res = 0;
for (int i = 0; i < edges.length; i++) {
if (edges[i][0] == 3) {
int a = edges[i][1];
int b = edges[i][2];
if (usa.isConnected(a, b)) {
res++;
} else {
usa.union(a, b);
usb.union(a, b);
}
}
}
for (int i = 0; i < edges.length; i++) {
int a = edges[i][1];
int b = edges[i][2];
if (edges[i][0] == 1) {
if (usa.isConnected(a, b)) {
res++;
} else {
usa.union(a, b);
}
} else if (edges[i][0] == 2) {
if (usb.isConnected(a, b)) {
res++;
} else {
usb.union(a, b);
}
}
}
return usa.cnt*usb.cnt>1 ? -1 : res;
}
class UnionSet {
int[] parent;
int cnt;
UnionSet(int n) {
cnt = n-1;
parent = new int[n];
for (int i = 1; i < n; i++) {
parent[i] = i;
}
}
public void union(int x, int y) {
int rx = find(x);
int ry = find(y);
if (rx == ry) return;
parent[rx] = ry;
cnt--;
}
public boolean isConnected(int x, int y) {
return find(x) == find(y);
}
public int find(int x) {
if (x != parent[x]) {
parent[x] = find(parent[x]);
}
return parent[x];
}
}
}
# 1314. 矩阵区域和
class Solution {
public int[][] matrixBlockSum(int[][] mat, int k) {
int row = mat.length, col = mat[0].length;
int[][] pre = new int[row+2*k+1][col+2*k+1];
for (int r = k+1; r <= row+2*k; r++) {
for (int c = k+1; c <= col+2*k; c++) {
int m = 0;
if (r-k-1 >= 0 && r-k-1 < row && c-k-1 >= 0 && c-k-1 < col) {
m = mat[r-k-1][c-k-1];
}
pre[r][c] = pre[r-1][c]+pre[r][c-1]-pre[r-1][c-1]+m;
}
}
int[][] ans = new int[row][col];
for (int r = k+1; r < row+k+1; r++) {
for (int c = k+1; c < col+k+1; c++) {
ans[r-k-1][c-k-1] = pre[r+k][c+k] - pre[r-k-1][c+k] - pre[r+k][c-k-1] + pre[r-k-1][c-k-1];
}
}
return ans;
}
}
# 397. 整数替换
class Solution {
Map<Long, Long> cache = new HashMap<>();
public int integerReplacement(int n) {
return (int)dfs(n);
}
private long dfs(long n) {
Long res = cache.get(n);
if (res != null) return res;
if (n == 1) return 0;
if (n % 2 == 0) {
res = dfs(n/2) + 1;
} else {
res = Math.min(dfs(n+1), dfs(n-1)) + 1;
}
cache.put(n, res);
return res;
}
}
# 323. 无向图中连通分量的数目
class Solution {
public int countComponents(int n, int[][] edges) {
UnionSet us = new UnionSet(n);
for (int[] e : edges) {
us.union(e[0], e[1]);
}
return us.cnt;
}
class UnionSet {
int[] parent;
int cnt;
UnionSet(int n) {
parent = new int[n];
cnt = n;
for (int i = 0; i < n; i++) {
parent[i] = i;
}
}
public int find(int x) {
if (x != parent[x]) {
parent[x] = find(parent[x]);
}
return parent[x];
}
public void union(int x, int y) {
int rx = find(x);
int ry = find(y);
if (rx == ry) return;
parent[rx] = ry;
cnt--;
}
}
}
# 1101. 彼此熟识的最早时间
class Solution {
public int earliestAcq(int[][] logs, int n) {
Arrays.sort(logs, (a, b)-> a[0]-b[0]);
UnionSet us = new UnionSet(n);
for (int[] log : logs) {
us.union(log[1], log[2]);
if (us.cnt == 1) {
return log[0];
}
}
return -1;
}
class UnionSet {
int[] parent;
int cnt;
UnionSet(int n) {
parent = new int[n];
cnt = n;
for (int i = 0; i < n; i++) {
parent[i] = i;
}
}
public int find(int x) {
if (x != parent[x]) {
parent[x] = find(parent[x]);
}
return parent[x];
}
public void union(int x, int y) {
int rx = find(x);
int ry = find(y);
if (rx == ry) return;
parent[rx] = ry;
cnt--;
}
}
}
# 1227. 飞机座位分配概率
class Solution {
public double nthPersonGetsNthSeat(int n) {
return n == 1 ? 1 : 0.5;
}
}
# 594. 最长和谐子序列
做复杂了
class Solution {
public int findLHS(int[] nums) {
Map<Integer, int[]> map = new HashMap<>();
int res = 0;
for (int i = 0; i < nums.length; i++) {
int[] def = new int[]{0, 0};
int[] min = map.getOrDefault(nums[i]-1, def);
int[] max = map.getOrDefault(nums[i]+1, def);
int[] equal = map.getOrDefault(nums[i], def);
int[] cur = new int[]{Math.max(min[1], equal[0])+1, Math.max(max[0], equal[1])+1};
map.put(nums[i], cur);
if (min[1] != 0 || max[0] != 0) {
res = Math.max(res, Math.max(cur[0], cur[1]));
}
}
return res == 1 ? 0 : res;
}
}
计数即可
class Solution {
public int findLHS(int[] nums) {
Map<Integer, Integer> map = new HashMap<>();
int res = 0;
for (int i = 0; i < nums.length; i++) {
map.put(nums[i], map.getOrDefault(nums[i], 0)+1);
}
for (Integer key : map.keySet()) {
if (map.containsKey(key+1)) {
res = Math.max(res, map.get(key)+map.get(key+1));
}
}
return res;
}
}
排序
class Solution {
public int findLHS(int[] nums) {
Arrays.sort(nums);
int l = 0, r = 0, res = 0;
while (r < nums.length) {
while (nums[r]-nums[l] > 1) {
l++;
}
if (nums[r]-nums[l] == 1){
res = Math.max(res, r-l+1);
}
r++;
}
return res;
}
}
# 559. N 叉树的最大深度
class Solution {
int res = 0;
public int maxDepth(Node root) {
dfs(root, 0);
return res;
}
private void dfs(Node node, int depth) {
if (node == null) {
res = Math.max(res, depth);
return;
}
if (node.children.size() == 0) {
res = Math.max(res, depth+1);
}
for (Node n : node.children) {
dfs(n, depth+1);
}
}
}
更简洁
class Solution {
public int maxDepth(Node root) {
if (root == null) return 0;
int res = 0;
for (Node n : root.children) {
res = Math.max(res, maxDepth(n));
}
return res+1;
}
}
# 253. 会议室 II
优先队列
class Solution {
public int minMeetingRooms(int[][] intervals) {
if(intervals == null || intervals.length == 0) {
return 0;
}
PriorityQueue<Integer> q = new PriorityQueue<>();
Arrays.sort(intervals, (a, b) -> a[0] - b[0]);
q.add(intervals[0][1]);
for(int i = 1; i < intervals.length; i++){
if(q.peek() <= intervals[i][0]){
q.poll();
}
q.add(intervals[i][1]);
}
return q.size();
}
}
# 767. 重构字符串
class Solution {
public String reorganizeString(String s) {
StringBuilder res = new StringBuilder();
int[] map = new int[26];
for (char c : s.toCharArray()) {
map[c-'a']++;
}
PriorityQueue<Integer> pq = new PriorityQueue<>((a, b) -> map[b]-map[a]);
for (int i = 0; i < 26; i++) {
if (map[i] == 0) continue;
pq.offer(i);
}
int last = -1;
while (pq.size() > 1) {
int first = pq.poll();
int second = pq.poll();
res.append((char) (first+'a'));
res.append((char) (second+'a'));
last = second;
map[first]--;
map[second]--;
if (map[second] > 0) {
pq.offer(first);
pq.offer(second);
} else if (map[first] > 0) {
pq.offer(first);
}
}
if (pq.size() > 0) {
if (pq.peek() == last || map[pq.peek()] > 1) {
return "";
}
res.append((char) (pq.poll()+'a'));
}
return res.toString();
}
}
while中另一种写法
class Solution {
public String reorganizeString(String s) {
StringBuilder res = new StringBuilder();
int[] map = new int[26];
for (char c : s.toCharArray()) {
map[c-'a']++;
}
PriorityQueue<Integer> pq = new PriorityQueue<>((a, b) -> map[b]-map[a]);
for (int i = 0; i < 26; i++) {
if (map[i] == 0) continue;
pq.offer(i);
}
int last = -1;
while (!pq.isEmpty()) {
if (pq.peek() == last) {
return "";
}
int first = pq.poll();
res.append((char) (first+'a'));
last = first;
map[first]--;
if (!pq.isEmpty()) {
int second = pq.poll();
res.append((char) (second+'a'));
last = second;
map[second]--;
if (map[second] > 0) {
pq.offer(first);
pq.offer(second);
} else if (map[first] > 0) {
pq.offer(first);
}
continue;
}
if (map[first] > 0) {
pq.offer(first);
}
}
return res.toString();
}
}
# 859. 亲密字符串
class Solution {
public boolean buddyStrings(String s, String goal) {
if (s.length() != goal.length()) {
return false;
}
int[] map = new int[26];
if (s.equals(goal)) {
for (int i = 0; i < s.length(); i++) {
map[s.charAt(i)-'a']++;
if (map[s.charAt(i)-'a'] > 1) {
return true;
}
}
return false;
} else {
int first = -1, second = -1;
for (int i = 0; i < s.length(); i++) {
if (s.charAt(i) != goal.charAt(i)) {
if (first == -1) {
first = i;
} else if (second == -1) {
second = i;
} else {
return false;
}
}
}
return second != -1 && s.charAt(first) == goal.charAt(second) && s.charAt(second) == goal.charAt(first);
}
}
}
# 358. K 距离间隔重排字符串
class Solution {
public String rearrangeString(String s, int k) {
if (k == 0) return s;
int[] map = new int[26];
for (char c : s.toCharArray()) {
map[c-'a']++;
}
PriorityQueue<Integer> pq = new PriorityQueue<>((a, b) -> {
if (map[b]-map[a] == 0) {
return a-b;
} else {
return map[b]-map[a];
}
});
StringBuilder res = new StringBuilder();
Queue<Integer> q = new LinkedList<>();
for (int i = 0; i < 26; i++) {
if (map[i] > 0) {
pq.offer(i);
}
}
while (pq.size() >= k) {
int kk = k;
while (q.size() < k) {
int cur = pq.poll();
kk--;
res.append((char) (cur+'a'));
map[cur]--;
q.offer(cur);
}
while (!q.isEmpty()) {
int cur = q.poll();
if (map[cur] > 0) {
pq.offer(cur);
}
}
}
while (pq.size() > 0) {
int cur = pq.poll();
if (map[cur] > 1) {
return "";
}
res.append((char) (cur+'a'));
}
return res.toString();
}
}
# 423. 从英文中重建数字
class Solution {
String[] digit = new String[]{"zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine"};
int[] priority = new int[]{0, 8, 6, 3, 2, 7, 5, 9, 4, 1};
public String originalDigits(String s) {
int[] map = new int[26];
for (char c : s.toCharArray()) {
map[c-'a']++;
}
StringBuilder res = new StringBuilder();
for (int i = 0; i < priority.length;) {
boolean ok = true;
for (char c : digit[priority[i]].toCharArray()) {
if (map[c-'a'] <= 0) {
ok = false;
break;
}
}
if (ok) {
for (char c : digit[priority[i]].toCharArray()) {
map[c-'a']--;
}
res.append(priority[i]);
} else {
i++;
}
}
char[] cs = res.toString().toCharArray();
Arrays.sort(cs);
return new String(cs);
}
}
# 700. 二叉搜索树中的搜索
递归
class Solution {
public TreeNode searchBST(TreeNode root, int val) {
if (root == null || root.val == val) return root;
return val > root.val ? searchBST(root.right, val) : searchBST(root.left, val);
}
}
# 519. 随机翻转矩阵
随机后,如果已随机过,从当前位置向两边搜索
class Solution {
Set<Integer> set = new HashSet<>();
Random random = new Random();
int m;
int n;
public Solution(int m, int n) {
this.m = m;
this.n = n;
}
public int[] flip() {
int l = random.nextInt(n*m), r = l;
while (l > 0 && set.contains(l)) l--;
while (r <= n*m && set.contains(r)) r++;
int res = 0;
if (!set.contains(l)) {
set.add(l);
res = l;
} else if (!set.contains(r)) {
set.add(r);
res = r;
}
return new int[]{res/n, res%n};
}
public void reset() {
set.clear();
}
}
map记录位置,随机区间缩小
class Solution {
Map<Integer, Integer> map = new HashMap<>();
int m, n, r;
Random random = new Random();
public Solution(int m, int n) {
this.m = m;
this.n = n;
this.r = m*n;
}
public int[] flip() {
int c = random.nextInt(r--);
int res = map.getOrDefault(c, c);
map.put(c, map.getOrDefault(r, r));
return new int[] {res/n, res%n};
}
public void reset() {
map.clear();
r = m*n;
}
}
# 593. 有效的正方形
正方形四个点有两条线,只有两种长度
class Solution {
public boolean validSquare(int[] p1, int[] p2, int[] p3, int[] p4) {
Set<Integer> set = new HashSet<>();
set.add(dist(p1, p2));
set.add(dist(p1, p3));
set.add(dist(p1, p4));
set.add(dist(p2, p3));
set.add(dist(p2, p4));
set.add(dist(p3, p4));
return !set.contains(0) && set.size() == 2;
}
private int dist(int[] a, int[] b) {
return (a[0]-b[0])*(a[0]-b[0]) + (a[1]-b[1])*(a[1]-b[1]);
}
}
# 786. 第 K 个最小的素数分数
优先队列
class Solution {
public int[] kthSmallestPrimeFraction(int[] arr, int k) {
PriorityQueue<int[]> pq = new PriorityQueue<>((a,b)-> {
return arr[a[0]]*arr[b[1]]-arr[a[1]]*arr[b[0]];
});
int n = arr.length;
for (int i = 1; i < n; i++) {
pq.offer(new int[]{0, i});
}
int[] res = null;
for (int i = 0; i < k; i++) {
res = pq.poll();
if (res[0] < res[1]-1) {
int[] p = new int[]{res[0]+1, res[1]};
pq.offer(p);
}
}
return new int[]{arr[res[0]], arr[res[1]]};
}
}
# 400. 第 N 位数字
模拟
class Solution {
public int findNthDigit(int n) {
if (n < 10) return n;
int d = 1;
long start = 9;
for (; d < 100; d++) {
if (n < d*start) {
start /= 10;
break;
}
n -= (start*d);
start *= 10;
}
int s = (int)Math.pow(10, d-1);
s += (n/d-1) + ((n%d>0)?1:0);
int p = (n%d==0?d:(n%d));
String str = String.valueOf(s);
return Integer.valueOf(str.substring(p-1, p));
}
}
# 1446. 连续字符
class Solution {
public int maxPower(String s) {
int cnt = 1;
int max = 1;
for (int i = 1; i < s.length(); i++) {
if (s.charAt(i) == s.charAt(i-1)) {
cnt++;
} else {
cnt = 1;
}
max = Math.max(max, cnt);
}
return max;
}
}
# 759. 员工空闲时间
优先队列
class Solution {
public List<Interval> employeeFreeTime(List<List<Interval>> schedule) {
List<Interval> res = new ArrayList<>();
PriorityQueue<int[]> pq = new PriorityQueue<>((a,b)->{
return schedule.get(a[0]).get(a[1]).start-schedule.get(b[0]).get(b[1]).start;
});
for (int i = 0; i < schedule.size(); i++) {
pq.offer(new int[]{i, 0});
}
int pre = -1;
while (!pq.isEmpty()) {
int[] t = pq.poll();
Interval poll = schedule.get(t[0]).get(t[1]);
if (poll.start > pre) {
res.add(new Interval(pre, poll.start));
}
if (poll.end > pre) {
pre = poll.end;
}
if (t[1]+1 < schedule.get(t[0]).size()) {
pq.offer(new int[]{t[0], t[1]+1});
}
}
res.remove(0);
return res;
}
}
# 729. 我的日程安排表 I
有序列表
class MyCalendar {
TreeMap<Integer, Integer> map;
public MyCalendar() {
map = new TreeMap<>();
}
public boolean book(int start, int end) {
Map.Entry<Integer, Integer> left = map.floorEntry(start);
Map.Entry<Integer, Integer> right = map.ceilingEntry(start);
if (left != null) {
if (start <= left.getKey() || start < left.getValue()) {
return false;
}
}
if (right != null) {
if (start >= right.getKey() || end > right.getKey()) {
return false;
}
}
map.put(start, end);
return true;
}
}
# 506. 相对名次
class Solution {
public String[] findRelativeRanks(int[] score) {
Map<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < score.length; i++) {
map.put(score[i], i);
}
Arrays.sort(score);
String[] res = new String[score.length];
int n = score.length;
for (int i = n-1; i >= 0; i--) {
String name = null;
if (i == n-1) {
name = "Gold Medal";
} else if (i == n-2) {
name = "Silver Medal";
} else if (i == n-3) {
name = "Bronze Medal";
} else {
name = String.valueOf(n-i);
}
res[map.get(score[i])] = name;
}
return res;
}
}
# 1606. 找到处理最多请求的服务器
有序列表+优先队列 模拟一遍过程,发现进来一个新请求时先看i%k的服务器是否空闲,非空闲则继续往后查看是否空闲即可。 需要算法支持: 1.某一个请求来的时间点上,将所有该时间点之前能处理完的服务器置为空闲(优先队列) 2.快速找到后面空闲的服务器(有序列表)
class Solution {
public List<Integer> busiestServers(int k, int[] arrival, int[] load) {
PriorityQueue<int[]> pq = new PriorityQueue<>((a,b)->{
return a[0]-b[0];
});
Map<Integer, int[]> map = new HashMap<>();
TreeMap<Integer, int[]> tree = new TreeMap<>();
for (int i = 0; i < k; i++) {
// {time, i, cnt}
int[] obj = new int[]{0, i, 0};
map.put(i, obj);
tree.put(i, obj);
}
for (int i = 0; i < arrival.length; i++) {
while (!pq.isEmpty() && pq.peek()[0] <= arrival[i]) {
int[] cur = pq.poll();
tree.put(cur[1], cur);
}
Map.Entry<Integer, int[]> entry = tree.ceilingEntry(i%k);
if (entry == null) {
entry = tree.ceilingEntry(0);
}
if (entry != null) {
int[] cur = entry.getValue();
cur[0] = arrival[i]+load[i];
cur[2]++;
pq.offer(cur);
tree.remove(entry.getKey());
}
}
int max = 0;
List<Integer> res = new ArrayList<>();
for (Map.Entry<Integer, int[]> entry : map.entrySet()) {
if (entry.getValue()[2] > max) {
max = entry.getValue()[2];
res.clear();
res.add(entry.getKey());
} else if (entry.getValue()[2] == max) {
res.add(entry.getKey());
}
}
return res;
}
}
# 1005. K 次取反后最大化的数组和
简单题,但是做法复杂了,导致实现时用时过长
class Solution {
public int largestSumAfterKNegations(int[] nums, int k) {
Arrays.sort(nums);
int res = 0;
for (int i = 0; i < nums.length; i++) {
if (k > 0) {
if (nums[i] < 0) {
res += (-nums[i]);
k--;
} else {
if (k % 2 == 0) {
res += nums[i];
} else {
if (i > 0 && nums[i] > (-nums[i-1])) {
res = res + nums[i-1] + nums[i-1] + nums[i];
} else {
res += (-nums[i]);
}
}
k = 0;
}
} else {
res += nums[i];
}
}
if (k != 0 && k % 2 == 1) {
int n = nums.length;
res = res + nums[n-1] + nums[n-1];
}
return res;
}
}
# 336. 回文对
class Solution {
public List<List<Integer>> palindromePairs(String[] words) {
Map<String, Integer> map = new HashMap<>();
for (int i = 0; i < words.length; i++) {
map.put(words[i], i);
}
List<List<Integer>> res = new ArrayList<>();
for (int i = 0; i < words.length; i++) {
String word = words[i];
Integer ii = map.get(reverse(word));
if (ii != null && ii != i) {
res.add(Arrays.asList(ii, i));
}
int end = word.length();
for (int k = 0; k <= end; k++) {
String left = "";
if (k > 0) {
left = word.substring(0, k);
}
String right = "";
if (k != end) {
right = word.substring(k, end);
}
if (check(left)) {
Integer index = map.get(reverse(right));
if (index != null) {
res.add(Arrays.asList(index, i));
}
}
if (check(right)) {
Integer index = map.get(reverse(left));
if (index != null) {
res.add(Arrays.asList(i, index));
}
}
}
}
return res;
}
private String reverse(String word) {
StringBuilder str = new StringBuilder(word);
return str.reverse().toString();
}
private boolean check(String word) {
int l = 0, r = word.length()-1;
if (l > r) return false;
while (l < r) {
if (word.charAt(l) != word.charAt(r)) {
return false;
}
l++;
r--;
}
return true;
}
}
# 1858. 包含所有前缀的最长单词
class Solution {
public String longestWord(String[] words) {
root = new TrieNode();
for (String word : words) {
insert(word);
}
int max = 0;
String res = "";
for (String word : words) {
if (search(word) && word.length() >= max) {
if (word.length() > max || word.compareTo(res) < 0) {
max = word.length();
res = word;
}
}
}
return res;
}
class TrieNode {
boolean end;
TrieNode[] tns = new TrieNode[26];
}
TrieNode root;
private void insert(String word) {
TrieNode p = root;
for (char w : word.toCharArray()) {
int u = w-'a';
if (p.tns[u] == null) p.tns[u] = new TrieNode();
p = p.tns[u];
}
p.end = true;
}
private boolean search(String word) {
TrieNode p = root;
for (char w : word.toCharArray()) {
int u = w-'a';
if (p.tns[u] == null || !p.tns[u].end) return false;
p = p.tns[u];
}
return true;
}
}
# 372. 超级次方
class Solution {
int mod = 1337;
public int superPow(int a, int[] b) {
return dfs(a, b, b.length-1);
}
private int dfs(int a, int[] b, int n) {
if (n == -1) return 1;
return quickPow(dfs(a, b, n-1), 10) * quickPow(a, b[n]) % mod;
}
private int quickPow(int a, int b) {
int ans = 1;
a %= mod;
while (b != 0) {
if ((b&1) != 0) {
ans = ans * a % mod;
}
a = a * a % mod;
b >>= 1;
}
return ans;
}
}
# 1816. 截断句子
class Solution {
public String truncateSentence(String s, int k) {
int i = 0, n = s.length();
for (; i <= n && k > 0; i++) {
if (i == n || s.charAt(i) == ' ') {
k--;
}
}
return s.substring(0, i-1);
}
}
# 1034. 边界着色
dfs
class Solution {
int[][] grid;
int[][] dir = new int[][]{{1, 0}, {0, 1}, {-1, 0}, {0, -1}};
int row;
int col;
boolean[][] vis;
int color;
public int[][] colorBorder(int[][] grid, int row, int col, int color) {
this.grid = grid;
this.row = grid.length;
this.col = grid[0].length;
vis = new boolean[this.row][this.col];
this.color = color;
dfs(row, col, grid[row][col]);
return grid;
}
private void dfs(int r, int c, int original) {
if (r < 0 || r >= row || c < 0 || c >= col) return;
vis[r][c] = true;
for (int i = 0; i < 4; i++) {
int nr = r+dir[i][0];
int nc = c+dir[i][1];
if (nr < 0 || nr >= row || nc < 0 || nc >= col || (!vis[nr][nc] && grid[nr][nc] != original)) {
grid[r][c] = color;
continue;
}
if (vis[nr][nc]) continue;
dfs(nr, nc, original);
}
}
}
# 1756. 设计最近使用(MRU)队列
class MRUQueue {
MTree tree;
int[] val;
int end;
public MRUQueue(int n) {
tree = new MTree(n);
val = new int[n+4000];
end = n;
for (int i = 1; i <= end; i++) {
val[i] = i;
}
}
public int fetch(int k) {
int l = 1, r = end;
while (l < r) {
int m = (l+r) >> 1;
if (m - tree.query(m) >= k) {
r = m;
} else {
l = m+1;
}
}
val[++end] = val[l];
tree.update(l);
return val[l];
}
class MTree {
int[] t;
MTree(int n) {
t = new int[n+4000];
}
public int lowbit(int x) {
return x & (-x);
}
public void update(int i) {
while (i < t.length) {
t[i] += 1;
i += lowbit(i);
}
}
public int query(int i) {
int res = 0;
while (i > 0) {
res += t[i];
i -= lowbit(i);
}
return res;
}
}
}
# 689. 三个无重叠子数组的最大和
递归,超时了
class Solution {
int k;
int max = 0;
List<Integer> maxPath = null;
public int[] maxSumOfThreeSubarrays(int[] nums, int k) {
this.k = k;
int[] pre = new int[nums.length-k+1];
for (int i = 0; i < k; i++) {
pre[0] += nums[i];
}
for (int i = 1; i < pre.length; i++) {
pre[i] = pre[i-1]-nums[i-1]+nums[i+k-1];
}
dfs(pre, 0, 0, 0, new ArrayList<>());
int[] res = new int[3];
int i = 0;
for (int p : maxPath) {
res[i++] = p;
}
return res;
}
private void dfs(int[] pre, int start, int sum, int cnt, List<Integer> path) {
if (cnt >= 3) {
if (sum > max) {
max = sum;
maxPath = new ArrayList<>(path);
}
return;
}
for (int i = start; i < pre.length; i++) {
path.add(i);
dfs(pre, i+k, sum+pre[i], cnt+1, path);
path.remove(path.size()-1);
}
}
}
正确解法
class Solution {
public int[] maxSumOfThreeSubarrays(int[] nums, int k) {
int[] sum = new int[nums.length-k+1];
for (int i = 0; i < k; i++) {
sum[0] += nums[i];
}
for (int i = 1; i < sum.length; i++) {
sum[i] = sum[i-1]-nums[i-1]+nums[i+k-1];
}
int n = sum.length;
int max = 0;
int index = 0;
int[] left = new int[n];
for (int i = 0; i < n; i++) {
if (sum[i] > max) {
max = sum[i];
index = i;
}
left[i] = index;
}
max = 0;
index = n-1;
int[] right = new int[n];
for (int i = n-1; i >= 0; i--) {
if (sum[i] >= max) {
max = sum[i];
index = i;
}
right[i] = index;
}
max = 0;
int[] res = null;
for (int i = k; i < n-k; i++) {
int v = sum[left[i-k]] + sum[i] + sum[right[i+k]];
if (v > max) {
max = v;
res = new int[]{left[i-k], i, right[i+k]};
}
}
return res;
}
}
# 794. 有效的井字游戏
class Solution {
public boolean validTicTacToe(String[] board) {
int xcnt = 0, ocnt = 0;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
char c = board[i].charAt(j);
if (c == 'X') {
xcnt++;
} else if (c == 'O') {
ocnt++;
}
}
}
if (xcnt < ocnt || xcnt - ocnt > 1) return false;
int xwin = win(board, 'X');
int owin = win(board, 'O');
if (xwin > 0 && owin > 0) return false;
if (xwin > 0 && xcnt - ocnt != 1) return false;
if (owin > 0 && xcnt != ocnt) return false;
return true;
}
private int win(String[] board, char c) {
int cnt = 0;
for (int i = 0; i < 3; i++) {
int scnt = 0;
for (int j = 0; j < 3; j++) {
if (board[i].charAt(j) == c) {
scnt++;
}
}
if (scnt == 3) {
cnt++;
}
}
for (int i = 0; i < 3; i++) {
int scnt = 0;
for (int j = 0; j < 3; j++) {
if (board[j].charAt(i) == c) {
scnt++;
}
}
if (scnt == 3) {
cnt++;
}
}
int upcnt = 0;
for (int i = 0; i < 3; i++) {
if (board[i].charAt(i) == c) {
upcnt++;
}
}
if (upcnt == 3) cnt++;
int dcnt = 0;
for (int i = 0; i < 3; i++) {
if (board[i].charAt(2-i) == c) {
dcnt++;
}
}
if (dcnt == 3) cnt++;
return cnt;
}
}
# 709. 转换成小写字母
class Solution {
public String toLowerCase(String s) {
char[] cs = s.toCharArray();
for (int i = 0; i < cs.length; i++) {
if (cs[i] >= 65 && cs[i] <= 90) {
cs[i] = (char) (cs[i]+32);
}
}
return new String(cs);
}
}
# 642. 设计搜索自动补全系统
class AutocompleteSystem {
TrieNode root;
String st = "";
public AutocompleteSystem(String[] sentences, int[] times) {
root = new TrieNode();
for (int i = 0; i < sentences.length; i++) {
insert(sentences[i], times[i]);
}
}
public List<String> input(char c) {
if (c == '#') {
insert(st, 1);
st = "";
return new ArrayList<>();
}
st += c;
return search(st);
}
class TrieNode {
boolean end = false;
TrieNode[] tns = new TrieNode[27];
int cnt = 0;
String st;
}
private void insert(String word, int cnt) {
TrieNode p = root;
for (int i = 0; i < word.length(); i++) {
char w = word.charAt(i);
int u = w == ' ' ? 26 : w-'a';
if (p.tns[u] == null) p.tns[u] = new TrieNode();
p = p.tns[u];
}
p.end = true;
p.cnt += cnt;
p.st = word;
}
private List<String> search(String word) {
TrieNode p = root;
for (int i = 0; i < word.length(); i++) {
char w = word.charAt(i);
int u = w == ' ' ? 26 : w-'a';
if (p.tns[u] == null) return new ArrayList<>();
p = p.tns[u];
}
List<Node> res = new ArrayList<>();
dfs(p, res);
PriorityQueue<Node> pq = new PriorityQueue<>((a, b)->{
if (a.cnt == b.cnt) {
return a.st.compareTo(b.st);
} else {
return b.cnt-a.cnt;
}
});
for (Node n : res) {
pq.offer(n);
}
List<String> ans = new ArrayList<>();
int k = 0;
while (!pq.isEmpty() && k < 3) {
ans.add(pq.poll().st);
k++;
}
return ans;
}
private void dfs(TrieNode p, List<Node> list) {
if (p == null) return;
if (p.end) list.add(new Node(p.st, p.cnt));
for (TrieNode next : p.tns) {
if (next == null) continue;
dfs(next, list);
}
}
class Node {
String st;
int cnt;
public Node(String st, int cnt) {
this.st = st;
this.cnt = cnt;
}
public String toString() {
return "{"+st+","+cnt+"}";
}
}
}
# 807. 保持城市天际线
class Solution {
public int maxIncreaseKeepingSkyline(int[][] grid) {
int r = grid.length;
int c = grid[0].length;
int[] row = new int[r];
int[] col = new int[c];
for (int i = 0; i < r; i++) {
for (int j = 0; j < c; j++) {
row[i] = Math.max(row[i], grid[i][j]);
col[j] = Math.max(col[j], grid[i][j]);
}
}
int res = 0;
for (int i = 0; i < r; i++) {
for (int j = 0; j < c; j++) {
res += (Math.min(row[i], col[j])-grid[i][j]);
}
}
return res;
}
}
# 630. 课程表 III
class Solution {
public int scheduleCourse(int[][] courses) {
Arrays.sort(courses, (a,b)->{
return a[1]-b[1];
});
PriorityQueue<int[]> pq = new PriorityQueue<>((a,b)->{
return b[0]-a[0];
});
int time = 0;
for (int i = 0; i < courses.length; i++) {
if (time+courses[i][0] <= courses[i][1]) {
pq.offer(courses[i]);
time += courses[i][0];
} else if (!pq.isEmpty() && pq.peek()[0] > courses[i][0]) {
time = time - pq.poll()[0] + courses[i][0];
pq.offer(courses[i]);
}
}
return pq.size();
}
}
# 851. 喧闹和富有
class Solution {
public int[] loudAndRich(int[][] richer, int[] quiet) {
int n = quiet.length;
List<Integer>[] adj = new ArrayList[n];
for (int i = 0; i < n; i++) {
adj[i] = new ArrayList<>();
}
for (int[] r : richer) {
adj[r[1]].add(r[0]);
}
int[] ans = new int[n];
Arrays.fill(ans, -1);
for (int i = 0; i < n; i++) {
dfs(adj, quiet, ans, i);
}
return ans;
}
private void dfs(List<Integer>[] adj, int[] quiet, int[] ans, int index) {
if (ans[index] != -1) {
return;
}
ans[index] = index;
for (int i : adj[index]) {
dfs(adj, quiet, ans, i);
if (quiet[ans[i]] < quiet[ans[index]]) {
ans[index] = ans[i];
}
}
}
}
# 997. 找到小镇的法官
class Solution {
public int findJudge(int n, int[][] trust) {
int[] visited = new int[n+1];
for (int i = 0; i < trust.length; i++) {
visited[trust[i][0]]--;
visited[trust[i][1]]++;
}
for (int i = 1; i <= n; i++) {
if (visited[i] == n-1) {
return i;
}
}
return -1;
}
}
# 1518. 换酒问题
class Solution {
public int numWaterBottles(int numBottles, int numExchange) {
int cnt = numBottles / (numExchange-1);
return (numBottles % (numExchange-1)) == 0 ? numBottles+cnt-1 : numBottles+cnt;
}
}
# 475. 供暖器
将houses存入treeSet中,排序heaters,遍历heaters,每两个供暖器距离的中间值mid,找到mid靠左和靠右的最近的house,当前house时便是供暖器应该辐射的范围,取两者的最大值,在跟所有的最大值求最大即可
class Solution {
public int findRadius(int[] houses, int[] heaters) {
Arrays.sort(heaters);
TreeSet<Integer> tree = new TreeSet<>();
for (int h : houses) {
tree.add(h);
}
int res = 0;
Integer first = tree.first();
if (first != null && first < heaters[0]) {
res = heaters[0]-first;
}
Integer last = tree.last();
if (last != null && last > heaters[heaters.length-1]) {
res = Math.max(res, last-heaters[heaters.length-1]);
}
int pre = heaters[0];
int mid = 0;
int mid2 = 0;
for (int i = 1; i < heaters.length; i++) {
int h = heaters[i];
mid = (pre + h) / 2;
mid2 = ((pre+h)%2) != 0 ? mid+1 : mid;
// left
int left = 0;
Integer rl = tree.floor(mid);
if (rl != null && rl > pre) {
left = rl-pre;
}
// right
int right = 0;
Integer rc = tree.ceiling(mid2);
if (rc != null && rc < h) {
right = h-rc;
}
// System.out.println("mid:"+mid+"; mid2:"+mid2+"; left:"+left+"; right:"+right);
res = Math.max(res, Math.max(left, right));
pre = h;
}
return res;
}
}
根据题解方式,使用二分,借助treeSet,将heaters存入;遍历houses时,去搜索heaters是否存在最近的供暖器。
class Solution {
public int findRadius(int[] houses, int[] heaters) {
TreeSet<Integer> tree = new TreeSet<>();
for (int h : heaters) {
tree.add(h);
}
int N = Integer.MAX_VALUE;
int res = 0;
for (int h : houses) {
int min = N;
Integer floor = tree.floor(h);
if (floor != null) {
min = h-floor;
}
Integer ceiling = tree.ceiling(h);
if (ceiling != null) {
min = Math.min(min, ceiling-h);
}
res = Math.max(res, min);
}
return res;
}
}
排序+双指针
class Solution {
public int findRadius(int[] houses, int[] heaters) {
Arrays.sort(houses);
Arrays.sort(heaters);
int i = 0, j = 0;
int res = Integer.MIN_VALUE;
while (i < houses.length) {
if (houses[i] <= heaters[j]) {
res = Math.max(res, heaters[j]-houses[i]);
i++;
} else {
if (j+1 < heaters.length && Math.abs(heaters[j+1]-houses[i]) <= Math.abs(houses[i]-heaters[j])) {
j++;
} else {
res = Math.max(res, houses[i]-heaters[j]);
i++;
}
}
}
return res;
}
}
# 1154. 一年中的第几天
class Solution {
static int[] mouth = new int[]{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
public int dayOfYear(String date) {
String[] ds = date.split("-");
int cnt = 0;
int mm = Integer.valueOf(ds[1]);
for (int i = mm-1; i >= 1; i--) {
cnt += mouth[i-1];
}
int yy = Integer.valueOf(ds[0]);
int dd = Integer.valueOf(ds[2]);
if ((yy%4==0 && yy%100!=0) || yy%400==0) {
if (mm > 2) {
cnt++;
}
}
return cnt+dd;
}
}
# 686. 重复叠加字符串匹配
暴力解,超时
class Solution {
public int repeatedStringMatch(String a, String b) {
int cnt = 1;
String aa = a;
while (aa.length() <= b.length()*100) {
if (aa.indexOf(b) != -1) return cnt;
cnt++;
aa = aa + a;
}
return -1;
}
}
找到复制次数的上下界
class Solution {
public int repeatedStringMatch(String a, String b) {
int cnt = 0;
StringBuilder aa = new StringBuilder();
while (aa.length() < b.length()) {
cnt++;
aa.append(a);
}
aa.append(a);
int index = aa.indexOf(b);
if (index != -1) {
return index+b.length() > a.length()*(cnt) ? cnt+1 : cnt;
}
return -1;
}
}
# 1044. 最长重复子串
二分法+字符串哈希
class Solution {
public String longestDupSubstring(String s) {
int n = s.length();
long[] h = new long[n+1];
long[] p = new long[n+1];
int P = 131; // 通常131不行就尝试1313131
p[0] = 1;
for (int i = 1; i <= n; i++) {
h[i] = h[i-1]*P + (s.charAt(i-1)-'a');
p[i] = p[i-1]*P;
}
String ans = "";
int l = 0, r = n;
while (l < r) {
int len = l + ((r-l+1)>>1);
String res = check(s, h, p, len);
if (res.length() != 0) {
l = len;
ans = res.length() > ans.length() ? res : ans;
} else {
r = len-1;
}
}
return ans;
}
private String check(String s, long[] h, long[] p, int len) {
String res = "";
Set<Long> set = new HashSet<>();
for (int i = 1; i <= s.length()-len+1; i++) {
long cur = h[i+len-1] - h[i-1]*p[len];
if (!set.add(cur)) {
res = s.substring(i-1, i+len-1);
break;
}
}
return res;
}
}
# 1705. 吃苹果的最大数目
class Solution {
public int eatenApples(int[] apples, int[] days) {
PriorityQueue<Integer> pq = new PriorityQueue<>((a, b)->{
int da = a+days[a], db = b+days[b];
if ((da)==(db)) {
return apples[a]-apples[b];
} else {
return da-db;
}
});
int d = 0, a = 0, n = apples.length;
while (!pq.isEmpty() || d < n) {
if (d < n && (apples[d] != 0 && days[d] != 0)) {
pq.offer(d);
}
int minus = 1;
while (minus > 0 && !pq.isEmpty()) {
int poll = pq.peek();
if (poll+days[poll] <= d || apples[poll] <= 0) {
pq.poll();
continue;
} else {
apples[poll]--;
}
minus--;
}
if (minus != 1) {
a++;
}
d++;
}
return a;
}
}
# 1609. 奇偶树
class Solution {
public boolean isEvenOddTree(TreeNode root) {
Queue<TreeNode> q = new LinkedList<>();
q.offer(root);
boolean odd = false;
while (!q.isEmpty()) {
int sz = q.size();
int pre = -1;
for (int i = 0; i < sz; i++) {
TreeNode cur = q.poll();
if (odd) {
if (cur.val % 2 != 0) return false;
if (pre != -1 && cur.val >= pre) return false;
} else {
if (cur.val % 2 == 0) return false;
if (pre != -1 && cur.val <= pre) return false;
}
pre = cur.val;
if (cur.left != null) q.offer(cur.left);
if (cur.right != null) q.offer(cur.right);
}
odd = !odd;
}
return true;
}
}
# 1078. Bigram 分词
class Solution {
public String[] findOcurrences(String text, String first, String second) {
String[] words = text.split(" ");
int i = 0, n = words.length-2;
List<String> res = new ArrayList<>();
while (i < n) {
if (first.equals(words[i]) && second.equals(words[i+1])) {
res.add(words[i+2]);
}
i++;
}
return res.toArray(new String[res.size()]);
}
}
# 825. 适龄的朋友
排序+二分,比较慢
class Solution {
public int numFriendRequests(int[] ages) {
Arrays.sort(ages);
int cnt = 0;
for (int i = 0; i < ages.length; i++) {
int edge = (int) (ages[i]*0.5+7);
cnt += binarySearch(ages, 0, i-1, edge);
cnt += binarySearch2(ages, i+1, ages.length-1, ages[i], edge);
}
return cnt;
}
private int binarySearch(int[] ages, int l, int r, int edge) {
int right = r;
if (r < 0 || ages[r] <= edge) return 0;
while (l < r) {
int mid = l + ((r-l)>>1);
if (ages[mid] > edge) {
r = mid;
} else {
l = mid+1;
}
}
return right-r+1;
}
private int binarySearch2(int[] ages, int l, int r,int t, int edge) {
int left = l;
if (l >= ages.length || ages[l] != t || ages[l] <= edge) return 0;
while (l < r) {
int mid = l + ((r-l+1)>>1);
if (ages[mid] == t) {
l = mid;
} else {
r = mid-1;
}
}
return l-left+1;
}
}
排序+双指针
class Solution {
public int numFriendRequests(int[] ages) {
Arrays.sort(ages);
int l = 0, r = 0, n = ages.length;
int cnt = 0;
for (int a : ages) {
if (a < 15) continue;
int e = (int) (a*0.5+7);
while (ages[l] <= e) {
l++;
}
while (r+1 < n && ages[r+1] <= a) {
r++;
}
cnt += r-l;
}
return cnt;
}
}
计数排序+前缀和
class Solution {
public int numFriendRequests(int[] ages) {
int[] cnt = new int[121];
for (int a : ages) {
cnt[a]++;
}
int[] pre = new int[121];
for (int i = 1; i < 121; i++) {
pre[i] = pre[i-1]+cnt[i];
}
int ans = 0;
for (int i = 15; i < 121; i++) {
if (cnt[i] == 0) continue;
ans += (pre[i]-pre[(int) (i*0.5+7)]-1)*cnt[i];
}
return ans;
}
}
# 472. 连接词
# 1995. 统计特殊四元组
class Solution {
public int countQuadruplets(int[] nums) {
int n = nums.length;
int cnt = 0;
for (int a = 0; a < n; a++) {
for (int b = a+1; b < n; b++) {
for (int c = b+1; c < n; c++) {
for (int d = c+1; d < n; d++) {
if (nums[a]+nums[b]+nums[c] == nums[d]) {
cnt++;
}
}
}
}
}
return cnt;
}
}
# 846. 一手顺子
排序+贪心
class Solution {
public boolean isNStraightHand(int[] hand, int groupSize) {
int n = hand.length;
if (n % groupSize != 0) return false;
Arrays.sort(hand);
int index = 0;
while (index < n) {
if (hand[index] == -1) {
index++;
continue;
}
int left = index;
int cnt = groupSize;
int right = left+1;
while (right < n && cnt > 1) {
if (hand[right] == -1 || hand[right] == hand[left]) {
right++;
continue;
}
if (hand[right] != hand[left]+1) {
return false;
}
hand[left] = -1;
left = right;
right++;
cnt--;
if (cnt <= 1) hand[left] = -1;
}
if (cnt > 1) return false;
index++;
}
return true;
}
}
# 1296. 划分数组为连续数字的集合
同846. 一手顺子
# 507. 完美数
纯暴力解
class Solution {
public boolean checkPerfectNumber(int num) {
int sum = 0;
int index = 1;
while (index < num) {
if (num % index == 0) {
sum += index;
}
if (sum > num) return false;
index++;
}
return sum == num;
}
}
规律:如果有一个因子d小于根号num,则一定有一个因子等于num/d
class Solution {
public boolean checkPerfectNumber(int num) {
if (num == 1) return false;
int sum = 1;
for (int i = 2; i*i <= num; i++) {
if (num % i == 0) {
sum += i;
if (i*i != num) {
sum += num/i;
}
}
}
return sum == num;
}
}