文章目录
- 题目:最大重复子字符串
- 题目: 面试题 16.07. 最大数值
- 题目: 最大字符串配对数目
- 题目: 字符串中第二大的数字
- 题目: 统计最大组的数目
- 题目: 删除每行中的最大值
- 题目: 二叉树的所有路径
- 题目: 七进制数
- 题目: N 叉树的最大深度
- 题目: 反转字符串中的单词 III
- 题目: 员工奖金 -- sql
- 题目: N 叉树的前序遍历
- 题目: N 叉树的后序遍历
- 题目: N 叉树的层序遍历
- 题目: 最长和谐子序列
- 题目: 种花问题
- 题目: 三个数的最大乘积
- 题目: 二叉树中第二小的节点
- 题目: 旋转字符串
- 题目: 比较含退格的字符串
- 题目: 和为零的 N 个不同整数
- 题目: 日期之间隔几天
- 题目: 通过翻转子数组使两个数组相等
- 题目: 第 k 个缺失的正整数
- 题目: 千位分隔数
- 总结
题目:最大重复子字符串
原题链接:最大重复子字符串
题解
方法:暴力延长word的重复次数并比较
,用contains()函数
public static int maxRepeating(String sequence, String word) {
int maxRepeat = 0;
StringBuilder repeatedWord = new StringBuilder(word);
// 循环尝试增加word的重复次数,直到不再是子字符串
while (sequence.contains(repeatedWord)) {
maxRepeat++;
repeatedWord.append(word);
}
return maxRepeat;
}
题目: 面试题 16.07. 最大数值
原题链接: 面试题 16.07. 最大数值
题解
方法:通过计算两个整数差值的符号位
表达式 a * (1 - sign) + b * sign
能够实现两个值的二选一效果
public int maximum(int a, int b) {
long diff = (long)a - (long)b;
long sign = (diff >>> 63) & 1;
return (int)(a * (1 - sign) + b * sign);
}
题目: 最大字符串配对数目
原题链接: 最大字符串配对数目
题解
public static int maximumNumberOfStringPairs(String[] words) {
HashSet<String> set = new HashSet<>();
int count = 0;
for (String word : words) {
String reversed = "" + word.charAt(1) + word.charAt(0);
// 检查反转字符串是否已经存在于 set 中
if (set.contains(reversed)) {
count++;
}
set.add(word);
}
return count;
}
题目: 字符串中第二大的数字
原题链接: 字符串中第二大的数字
题解
方法1:
public static int secondHighest(String s) {
Set<Integer> set = new HashSet<>();
for (char c : s.toCharArray()) {
if (Character.isDigit(c)) {
set.add(c - '0');
}
}
int firstMax = -1;
int secondMax = -1;
for (Integer i : set) {
if (i > firstMax) {
secondMax = firstMax;
firstMax = i;
} else if (i > secondMax && i < firstMax) {
secondMax = i;
}
}
return secondMax;
}
方法2:
先找到最大值删除,如果set不为空,继续寻找最大值(答案)
public static int secondHighest11(String s) {
Set<Integer> set = new HashSet<>();
for (char c : s.toCharArray()) {
if (Character.isDigit(c)) {
set.add(c - '0');
}
}
int maxValue = -1;
for (Integer i : set) {
if (i > maxValue) {
maxValue = i;
}
}
set.remove(maxValue);
if (set.size() == 0) return -1;
maxValue = -1;
for (Integer i : set) {
if (i > maxValue) {
maxValue = i;
}
}
return maxValue;
}
题目: 统计最大组的数目
原题链接: 统计最大组的数目
题解
方法:利用 map 将相同的数位和作为键
(哈希表
)
public static int sumDigit(int i) {
int res = 0;
while (i > 0) {
res += i % 10;
i /= 10;
}
return res;
}
public static int countLargestGroup(int n) {
int maxCnt = 0;
HashMap<Integer, Integer> map = new HashMap<>();
for (int i = 1; i <= n; i++) {
int sum = sumDigit(i);
int count = map.getOrDefault(sum, 0) + 1;
map.put(sum, count);
maxCnt = Math.max(maxCnt, count);
}
int res = 0;
for (Integer value : map.values()) {
if (value == maxCnt) {
res++;
}
}
return res;
}
题目: 删除每行中的最大值
原题链接: 删除每行中的最大值
题解
方法:通过逐列查找每一行未使用的最大值,并将其标记为已使用,然后将每列的最大值累加得到最终结果。主要利用 used 数组来跟踪已经处理过的元素
。
public boolean[][] used = new boolean[51][51];
// 找到一行中最最大的元素 并标记已处理
public int findMaxByRow(int[][] grid, int row) {
int maxValue = -1;
int maxIndex = -1;
for (int i = 0; i < grid[0].length; i++) {
if (!used[row][i] && grid[row][i] > maxValue) {
maxValue = grid[row][i];
maxIndex = i;
}
}
if (maxIndex != -1) {
used[row][maxIndex] = true;
}
return maxValue;
}
public int deleteGreatestValue(int[][] grid) {
int res = 0;
for (int j = 0; j < grid[0].length; j++) {
int maxValue = -1;
for (int i = 0; i < grid.length; i++) {
int maxByRow = findMaxByRow(grid, i);
if (maxValue < maxByRow)
maxValue = maxByRow;
}
res += maxValue;
}
return res;
}
题目: 二叉树的所有路径
原题链接: 二叉树的所有路径
题解
方法:创建两个队列,一个用于存储当前节点 (nodeQueue),另一个用于存储从根节点到当前节点的路径 (pathQueue)。将根节点和路径 “root.val” 入队。
先去看一下二叉树层次遍历,然后看这个题,就很简单了
public List<String> binaryTreePaths(TreeNode root) {
List<String> paths = new ArrayList<String>();
if (root == null) {
return paths;
}
Queue<TreeNode> nodeQueue = new LinkedList<TreeNode>();
Queue<String> pathQueue = new LinkedList<String>();
nodeQueue.offer(root);
pathQueue.offer(Integer.toString(root.val));
while (!nodeQueue.isEmpty()) {
TreeNode node = nodeQueue.poll();
String path = pathQueue.poll();
if (node.left == null && node.right == null) {
paths.add(path);
} else {
if (node.left != null) {
nodeQueue.offer(node.left);
pathQueue.offer(new StringBuffer(path).append("->").append(node.left.val).toString());
}
if (node.right != null) {
nodeQueue.offer(node.right);
pathQueue.offer(new StringBuffer(path).append("->").append(node.right.val).toString());
}
}
}
return paths;
}
题目: 七进制数
原题链接: 七进制数
题解
方法:除7取于法
,余数倒着写
public static String convertToBase7(int num) {
if (num == 0) return "0";
StringBuilder res = new StringBuilder();
int flag = num < 0 ? -1 : 1;
num = Math.abs(num);
while (num > 0) {
res.append(num % 7);
num /= 7;
}
return flag == 1 ? res.reverse().toString() : "-" + res.reverse().toString();
}
题目: N 叉树的最大深度
原题链接: N 叉树的最大深度
题解
方法1:广度优先搜索
在每次进入 while 循环时,首先获取 queue 中的节点数量,这代表当前层的节点数
。接着,逐一处理这些节点,将它们的子节点添加到 queue 中
public int maxDepth(Node root) {
if (root == null) return 0;
int res = 0;
LinkedList<Node> queue = new LinkedList<>();
queue.offer(root);
while (!queue.isEmpty()) {
res += 1;
int size = queue.size();
while (size > 0) {
Node node = queue.poll();
queue.addAll(node.children);
size--;
}
}
return res;
}
方法2: 深度优先搜索
public int maxDepth(Node root) {
if (root == null) return 0;
int maxDepth = 0;
List<Node> children = root.children;
for (Node child : children) {
int childDepth = maxDepth(child);
maxDepth = Math.max(maxDepth, childDepth);
}
return maxDepth+1;
}
题目: 反转字符串中的单词 III
原题链接: 反转字符串中的单词 III
题解
方法:主要通过 StringBuilder 的 reverse() 方法来反转每个单词
public String reverseWords(String s) {
String[] words = s.split(" ");
StringBuilder res = new StringBuilder();
for (String word : words) {
res.append(new StringBuilder(word).reverse()).append(" ");
}
return res.toString().trim();
}
题目: 员工奖金 – sql
原题链接: 员工奖金
题解
方法:因为奖金为空的也要用null表示。因为加一个:or b.bonus is null
select e.name,b.bonus
from Employee as e left join Bonus as b on e.empId=b.empId
where b.bonus < 1000 or b.bonus is null;
题目: N 叉树的前序遍历
原题链接: N 叉树的前序遍历
题解
方法:N 叉树的前序遍历与二叉树的前序遍历的思路和方法基本一致
前序遍历:根左右
public List<Integer> preorder(Node root) {
List<Integer> res = new ArrayList<>();
helper(root, res);
return res;
}
public void helper(Node root, List<Integer> res) {
if (root == null) return;
res.add(root.val); // 访问根元素
for (Node child : root.children) {
helper(child, res);
}
}
二叉树前序遍历:
List<Integer> res = new ArrayList<>();
// 前序遍历
public List<Integer> preorderTraversal(TreeNode root) {
if (root == null) return res;
res.add(root.val);
preorderTraversal(root.left);
preorderTraversal(root.right);
return res;
}
题目: N 叉树的后序遍历
原题链接: N 叉树的后序遍历
题解
public List<Integer> postorder(Node root) {
List<Integer> res = new ArrayList<>();
helper(root, res);
return res;
}
private void helper(Node root, List<Integer> res) {
if (root == null) return;
for (Node child : root.children) {
helper(child, res);
}
res.add(root.val);
}
题目: N 叉树的层序遍历
原题链接: N 叉树的层序遍历
题解
方法:和二叉树层次遍历相同,借助队列queue
public List<List<Integer>> levelOrder(Node root) {
List<List<Integer>> res = new ArrayList<>();
if (root == null) return res;
LinkedList<Node> queue = new LinkedList<>();
queue.offer(root);
while (!queue.isEmpty()) {
int size = queue.size();
ArrayList<Integer> list = new ArrayList<>();
while (size > 0) {
Node node = queue.poll();
list.add(node.val);
for (Node child : node.children) {
queue.offer(child);
}
size--;
}
res.add(list);
}
return res;
}
题目: 最长和谐子序列
原题链接: 最长和谐子序列
题解
方法:这个方法利用 HashMap 记录每个数字的出现次数,并通过检查每个数字和它的下一个数字是否同时存在来寻找和谐子数组的最大长度。
public static int findLHS(int[] nums) {
int res = 0;
HashMap<Integer, Integer> map = new HashMap<>();
for (int num : nums) {
map.put(num, (1 + map.getOrDefault(num, 0)));
}
for (Integer i : map.keySet()) {
if (map.containsKey(i + 1)) {
res = Math.max(res, map.get(i) + map.get(i + 1));
}
}
return res;
}
题目: 种花问题
原题链接: 种花问题
题解
方法:通过遍历花坛,检查每个位置是否可以放置花朵,确保前后位置均为空
。它在合适的位置放置花朵,并计算可以放置的总花朵数,最终判断是否能满足所需的花朵数量。
public boolean canPlaceFlowers(int[] flowerbed, int n) {
int count = 0;
for (int i = 0; i < flowerbed.length; i++) {
// 如果当前位置是 0 且前后位置也为空(边界条件也要考虑)
if (flowerbed[i] == 0 &&
(i == 0 || flowerbed[i - 1] == 0) &&
(i == flowerbed.length - 1 || flowerbed[i + 1] == 0)) {
// 放置花朵
flowerbed[i] = 1;
count++;
}
}
return count >= n;
}
题目: 三个数的最大乘积
原题链接: 三个数的最大乘积
题解
方法:排序
我第一想法没考虑到排序,感觉刷迷糊了😭
public int maximumProduct(int[] nums) {
Arrays.sort(nums);
return Math.max(nums[0] * nums[1] * nums[nums.length - 1], nums[nums.length - 1] * nums[nums.length - 2] * nums[nums.length - 3]);
}
题目: 二叉树中第二小的节点
原题链接: 二叉树中第二小的节点
题解
方法1:
public static int findSecondMinimumValue(TreeNode root) {
HashSet<Integer> set = new HashSet<>();
helper(root, set);
if (set.size() < 2) return -1;
int min1 = Integer.MAX_VALUE, min2 = Integer.MAX_VALUE;
for (int i : set) {
if (i < min1) {
min1 = i;
}
}
set.remove(min1);
for (int i : set) {
if (i < min2) {
min2 = i;
}
}
return min2;
}
public static void helper(TreeNode root, HashSet<Integer> set) {
if (root == null) return;
set.add(root.val);
helper(root.left, set);
helper(root.right, set);
}
方法:
public static int findSecondMinimumValue(TreeNode root) {
if (root == null) return -1;
// 初始最小值为根节点的值
int firstMin = root.val;
// 使用递归找出第二小的值
return findSecondMinimum(root, firstMin);
}
private static int findSecondMinimum(TreeNode root, int firstMin) {
if (root == null) return -1;
// 如果当前节点值大于最小值,可能是第二小的值
if (root.val > firstMin) return root.val;
// 递归查找左右子树中的第二小值
int left = findSecondMinimum(root.left, firstMin);
int right = findSecondMinimum(root.right, firstMin);
// 处理左右子树的值
if (left != -1 && right != -1) {
return Math.min(left, right);
}
return Math.max(left, right);
}
题目: 旋转字符串
原题链接: 旋转字符串
题解
方法1:将输入字符串s转换为字符链表,然后通过循环将链表的最后一个元素移动到第一个位置,每次旋转后都检查是否与目标字符串goal相等,如果相等则返回true。如果旋转了整个字符串长度次后仍未找到匹配,则返回false。
public boolean rotateString(String s, String goal) {
if (s.length() != goal.length()) return false;
LinkedList<Character> list = new LinkedList<>();
char[] charArray = s.toCharArray();
for (char c : charArray) {
list.addLast(c);
}
for (int i = 0; i < list.size(); i++) {
list.addFirst(list.removeLast());
StringBuilder builder = new StringBuilder();
list.stream().forEach(builder::append);
if (builder.toString().equals(goal)) return true;
}
return false;
}
方法2:搜索子字符串
如果将字符串 s 拼接到自身形成 doubled,那么所有可能的旋转版本都将成为 doubled 的子串。
public boolean rotateString(String s, String goal) {
// 先检查长度是否相同,不同则直接返回 false
if (s.length() != goal.length()) {
return false;
}
// 将 s 重复两次
String doubled = s + s;
// 检查 goal 是否是 doubleS 的子串
return doubled.contains(goal);
}
题目: 比较含退格的字符串
原题链接: 比较含退格的字符串
题解
方法:处理过程中,将每个字符串中的字符按顺序添加到 StringBuilder 中,并且遇到 '#' 时删除最后一个字符
。最终,方法通过比较两个处理后的字符串来确定它们是否相等。
public static boolean backspaceCompare(String s, String t) {
return extracted(s).equals(extracted(t));
}
public static String extracted(String s) {
StringBuilder res = new StringBuilder();
for (char c : s.toCharArray()) {
if (c == '#') {
if (res.length() > 0) res.deleteCharAt(res.length() - 1);
} else {
res.append(c);
}
}
return res.toString();
}
题目: 和为零的 N 个不同整数
原题链接: 和为零的 N 个不同整数
题解
方法:
- 如果 n 是偶数,生成对称的正负数对。
- 如果 n 是奇数,生成对称的正负数对并在中间加一个 0
public static int[] sumZero(int n) {
int[] arr = new int[n];
// 填充数组
for (int i = 0; i < n / 2; i++) {
arr[i] = i + 1; // 生成正数
arr[n - i - 1] = -(i + 1); // 生成对应的负数
}
// 如果 n 是奇数,填入中间的 0
if (n % 2 != 0) {
arr[n / 2] = 0;
}
return arr;
}
题目: 日期之间隔几天
原题链接: 日期之间隔几天
题解
方法: toEpochDay()
方法返回的是从 1970-01-01
开始到指定日期的天数。(1970 年 1 月 1 日被称为“纪元”或“epoch”)
用这个api这道题直接走捷径
import java.time.LocalDate;
public int daysBetweenDates(String date1, String date2) {
LocalDate d1 = LocalDate.parse(date1);
LocalDate d2 = LocalDate.parse(date2);
return (int) Math.abs(d1.toEpochDay()-d2.toEpochDay());
}
题目: 通过翻转子数组使两个数组相等
原题链接: 通过翻转子数组使两个数组相等
题解
方法1:
大意了,没仔细读题,这方法臃肿了。但是发现一个不起眼的错误。
public static boolean canBeEqual(int[] target, int[] arr) {
Map<Integer, Integer> map = new HashMap<>();
Set<Integer> set = new HashSet<>();
for (int i : target) {
set.add(i);
map.put(i, map.getOrDefault(i, 0) + 1);
}
int cnt = 0;
Map<Integer, Integer> map1 = new HashMap<>();
for (int i : arr) {
map1.put(i, map1.getOrDefault(i, 0) + 1);
}
for (Integer i : map.keySet()) {
if (map1.containsKey(i) && (map.get(i).equals(map1.get(i)))) {
cnt += 1;
}
}
return cnt == set.size();
}
当我在力扣上提交,发现就一个通不过,所以我就去本地IDEA调试了下,发现Integer比较出错了。知道这个知识点,但是实际用的适合却忽略了😭
改为 (map.get(i).equals(map1.get(i)))
,然后就通过了
Integer 对象在一定范围内(-128 到 127)是缓存
的,因此在这个范围内的 Integer 对象是相同的。但是,超出这个范围的 Integer 对象则会在不同的对象实例中创建,即使它们的值相等,== 比较也可能会失败。
方法2:先排序然后比较数组
因为说了数组长度相同,所以直接排序,然后Arrays工具类中equals方法比较即可出答案
Arrays.equals 是一个用于比较两个数组是否相等的静态方法
public static boolean canBeEqual(int[] target, int[] arr) {
Arrays.sort(target);
Arrays.sort(arr);
return Arrays.equals(target, arr);
}
题目: 第 k 个缺失的正整数
原题链接: 第 k 个缺失的正整数
题解
方法:利用set记录已经存在的
public int findKthPositive(int[] arr, int k) {
HashSet<Integer> set = new HashSet<>();
for (int i : arr) {
set.add(i);
}
int cnt = 0;
for (int i = 1; i <= arr[arr.length - 1] + k; i++) {
if (!set.contains(i)) {
cnt += 1;
if (cnt == k) {
return i;
}
}
}
return 0;
}
题目: 千位分隔数
原题链接: 千位分隔数
题解
在处理字符串时,使用 append 方法通常比 insert 更高效。
方法1:用StringBuilder的insert方法
public String thousandSeparator(int n) {
if (n == 0) return "0";
StringBuilder sb = new StringBuilder();
int cnt = 0;
while (n > 0) {
if (cnt == 3) {
sb.insert(0, '.');
cnt = 0;
}
sb.insert(0, n % 10);
cnt += 1;
n /= 10;
}
return sb.toString();
}
方法2:用StringBuilder的append方法
public String thousandSeparator(int n) {
if (n == 0) return "0";
StringBuilder sb = new StringBuilder();
int cnt = 0;
while (n > 0) {
if (cnt == 3 ) {
sb.append('.');
cnt=0;
}
sb.append(n % 10);
n /= 10;
cnt++;
}
return sb.reverse().toString();
}
总结
- 拿到一个题目要
认真读题
(建议读2遍),没思路可以看一下提示,有时候提示会给你一些解题思路的 - 不要被给的输入输出示例迷惑了,有时候会干扰你解题的