class Solution {
public void merge(int[] nums1, int m, int[] nums2, int n) {
// 这个循环将 nums2 中的元素逐个复制到 nums1 中从索引 m 开始的位置
for(int i = 0; i < n; i++) {
nums1[i + m] = nums2[i];
}
// 使用 Java 内置的 Arrays.sort 方法对合并后的 nums1 数组进行排序
Arrays.sort(nums1);
}
}
class Solution {
public int removeElement(int[] nums, int val) {
// 定义一个指针 l ,初始值为 0 ,用于标记新数组的位置
int l = 0;
// 遍历 nums 数组中的每个元素
for (int num : nums) {
// 如果当前元素等于指定的值 val ,则跳过本次循环
if (num == val) {
continue;
}
// 将不等于 val 的元素放到新位置(由 l 指示)
nums[l] = num;
// 移动指针 l ,指向下一个位置
l = l + 1;
}
// 返回新数组的长度(即不等于 val 的元素个数)
return l;
}
}
class Solution {
public int removeDuplicates(int[] nums) {
// 如果数组长度为 0,直接返回 0
if (nums.length == 0) {
return 0;
}
// 初始化慢指针 i 为 1,指向数组第二个元素
int i = 1;
// 使用快指针 j 遍历数组,从第二个元素开始(索引为 1)
for (int j = 1; j < nums.length; j++) {
// 如果快指针指向的元素和慢指针前一个位置的元素不相等
if (nums[i - 1] != nums[j]) {
// 将快指针指向的元素赋值给慢指针位置的元素
nums[i] = nums[j];
// 慢指针向后移动一位
i = i + 1;
}
}
// 返回慢指针的位置,即去除重复元素后数组的长度
return i;
}
}
class Solution {
public int removeDuplicates(int[] nums) {
// 如果数组长度小于等于2,则直接返回数组长度
if (nums.length <= 2) {
return nums.length;
}
// 初始化两个指针,slow用于记录新数组的长度和待插入元素的位置,fast用于遍历原数组
int slow = 2;
int fast = 2;
// 开始遍历数组
while (fast < nums.length) {
// 当发现当前元素和前面两个待保持的元素不同时,说明当前元素可以保留
if (nums[slow - 2] != nums[fast]) {
// 将当前fast指向的元素放到slow指向的位置
nums[slow] = nums[fast];
// 更新slow指针,指向下一个待插入的位置
++slow;
}
// 更新fast指针,继续往后遍历
++fast;
}
// 返回新数组的长度
return slow;
}
}
class Solution {
public int majorityElement(int[] nums) {
// 对给定的整数数组 nums 进行排序
Arrays.sort(nums);
// 返回排序后数组中间位置的元素
return nums[nums.length / 2];
}
}
class Solution {
// 定义一个公共静态方法 rotate,接收一个整数数组 nums 和旋转步数 k
public void rotate(int[] nums, int k) {
// // 创建一个与 nums 长度相同的新数组 newArr
int[] newArr = new int[nums.length];
// // 遍历原数组 nums
for (int i = 0; i < nums.length; i++) {
// 根据当前索引 i 和旋转步数 k 计算新数组中应放置的索引
// 使用 % 运算符确保索引在数组范围内
newArr[(i + k) % nums.length] = nums[i];
}
// 将新数组 newArr 的内容复制到原数组 nums 中
System.arraycopy(newArr, 0, nums, 0, nums.length);
}
}
class Solution {
public int maxProfit(int[] prices) {
// [7,1,5,3,6,4]
int minPrice = prices[0];
int ans = 0;
for (int i = 0; i < prices.length; i++) {
minPrice = Math.min(minPrice, prices[i]);
ans = Math.max(ans, prices[i] - minPrice);
}
return ans;
}
}
class Solution {
// 定义一个公共方法 maxProfit,接收一个整数数组 prices,表示股票价格
public int maxProfit(int[] prices) {
// 初始化 result 为 0,用于累计最大利润
int result = 0;
// 从第二天开始遍历价格数组
for (int i = 1; i < prices.length; i++) {
// 如果当前价格高于前一天的价格
if (prices[i - 1] < prices[i]) {
// 累计利润:当前价格减去前一天的价格
result += (prices[i] - prices[i - 1]);
}
}
// 返回累计的最大利润
return result;
}
}
class Solution {
// 定义一个公共方法 canJump,接收一个整数数组 nums,表示每个位置的最大跳跃长度
public boolean canJump(int[] nums) {
// 初始化一个变量 rightmost,用于记录能跳到的最远位置
int rightMost = 0;
// 遍历数组
for (int i = 0; i < nums.length; i++) {
// 如果当前索引 i 在能跳跃的范围内
if (i <= rightMost) {
// 更新 rightmost 为当前位置可以跳跃到的最远位置
rightMost = Math.max(rightMost, i + nums[i]);
// 如果能跳到或超过最后一个位置,返回 true
if (rightMost >= nums.length - 1) {
return true;
}
}
}
// 如果遍历结束仍未能跳到最后一个位置,返回 false
return false;
}
}
class Solution {
// 定义一个公共方法 jump,接收一个整数数组 nums,表示每个位置的最大跳跃长度
public int jump(int[] nums) {
// maxPosition 初始化,用于记录当前能跳到的最远位置
int maxPosition = 0;
// 初始化 end,表示当前的跳跃终点
int end = 0;
// 初始化 steps,表示跳跃的次数
int steps = 0;
// 遍历数组,直到倒数第二个元素(因为最后一个不需要跳跃)
for (int i = 0; i < nums.length - 1; i++) {
// 更新最远位置,可以跳到的最大索引
maxPosition = Math.max(maxPosition, i + nums[i]);
// 如果到达当前跳跃的终点
if (i == end) {
// 更新跳跃终点为 maxPosition
end = maxPosition;
// 增加跳跃次数
steps++;
}
}
// 返回总的跳跃次数
return steps;
}
}
class Solution {
// 定义一个公共方法 hIndex,接收一个整数数组 citations,表示引文次数
public int hIndex(int[] citations) {
// 对引文次数数组进行排序
Arrays.sort(citations);
// 初始化索引 i 为数组的最后一个元素
int i = citations.length - 1;
// 初始化 h 为 0,用于记录 h 指数
int h = 0;
// 遍历数组,直到索引 i 小于 0 或当前引文次数 citations[i] 小于等于 h
while (i >= 0 && citations[i] > h) {
// 每次循环,增加 h 的值
h++;
// 移动到前一个引文次数
i--;
}
// 返回最终计算的 h 指数
return h;
}
}
class RandomizedSet {
// 用于存储元素的列表
List<Integer> nums;
// 用于存储元素及其在 nums 列表中索引的映射
Map<Integer, Integer> indices;
// 随机数生成器
Random random;
public RandomizedSet() {
// 初始化 nums 列表
nums = new ArrayList<>();
// 初始化索引映射
indices = new HashMap<>();
// 初始化随机数生成器
random = new Random();
}
// 插入一个新的元素 val
public boolean insert(int val) {
// 如果 val 已存在于 indices 中,返回 false
if (indices.containsKey(val)) {
return false;
}
// 记录 val 对应的索引
indices.put(val, nums.size());
// 将 val 添加到 nums 列表的末尾
nums.add(val);
return true;
}
// 移除元素 val
public boolean remove(int val) {
// 如果 val 不存在,返回 false
if (!indices.containsKey(val)) {
return false;
}
// 获取 val 的索引
int index = indices.get(val);
// 获取 nums 列表最后一个元素
int last = nums.get(nums.size() - 1);
// 将最后一个元素放到 val 的位置上
nums.set(index, last);
// 更新 last 元素在 indices 中的索引
indices.put(last, index);
// 从 nums 列表中移除最后一个元素
nums.remove(nums.size() - 1);
// 从 indices 中移除 val
indices.remove(val);
// 返回 true,表示移除成功
return true;
}
// 返回一个随机元素
public int getRandom() {
// 生成一个随机索引
int randomIndex = random.nextInt(nums.size());
// 返回随机索引对应的元素
return nums.get(randomIndex);
}
}
/**
* Your RandomizedSet object will be instantiated and called as such:
* RandomizedSet obj = new RandomizedSet();
* boolean param_1 = obj.insert(val);
* boolean param_2 = obj.remove(val);
* int param_3 = obj.getRandom();
*/
class Solution {
/**
* 题目:除自身以外数组的乘积
* 思路:计算当前元素,所有左右前缀数组乘积,然后再遍历原数组,当前位置的左右前缀乘积再相乘
*
* 输入:nums = {1,2,3,4}
* 输出:answer = {24,12,8,6}
* @param nums 输入数组
* @return 除自身以外数组的乘积
*/
public static int[] productExceptSelf(int[] nums) {
// 初始化左前缀乘积数组
int[] leftSum = new int[nums.length];
// 初始化右前缀乘积数组
int[] rightSum = new int[nums.length];
// 边界定义,索引0左前缀无元素,初始化为1
leftSum[0] = 1;
// 排除边界开始计算,当前元素后一个元素 * 后一个元素左前缀乘积,即是当前元素的左前缀乘积
for (int i = 1; i < nums.length; i++) {
leftSum[i] = nums[i - 1] * leftSum[i - 1];
}
// 边界定义,索引nums.length -1右前缀无元素,右前缀乘积初始化为1
rightSum[nums.length - 1] = 1;
// 排除边界开始计算,当前元素前一个元素 * 前一个元素右前缀乘积,即是当前元素的右前缀乘积
for (int i = nums.length - 2; i >= 0; i--) {
rightSum[i] = nums[i + 1] * rightSum[i + 1];
}
int[] result = new int[nums.length];
// 当前元素的所有乘积,即是当前元素的所有左前缀与右前缀乘积
for (int i = 0; i< nums.length; i++) {
result[i] = leftSum[i] * rightSum[i];
}
System.out.println(Arrays.toString(result));
return result;
}
}
class Solution {
// 方法 canCompleteCircuit 接收两个列表 gas 和 cost,返回可以完成一圈的起始站点索引
public int canCompleteCircuit(int[] gas, int[] cost) {
// 用于累计当前的净油量
int sum = 0;
// 用于记录当前的最大净油量
int sumMax = 0;
// 用于记录可能的起始站点
int ans = 0;
// 从后往前遍历 gas 和 cost 列表
for (int i = gas.length - 1; i >= 0; i--) {
// 计算当前站点的净油量
sum += gas[i] - cost[i];
// 更新当前的最大净油量
sumMax = Math.max(sum, sumMax);
// 如果当前的净油量大于等于最大净油量,记录当前站点为可能的起始点
if (sum >= sumMax) {
ans = i;
}
}
// 如果总的净油量大于等于 0,返回可能的起始点;否则返回 -1
return sum >= 0 ? ans : -1;
}
}
class Solution {
// 方法:将罗马数字转换为整数
public int romanToInt(String s) {
// 初始化累加器,用于存储转换后的整数值
int sum = 0;
// 获取第一个字符的值
int preNum = getValue(s.charAt(0));
// 遍历字符串的每个字符,从第二个字符开始
for (int i = 1; i < s.length(); i++) {
// 获取当前字符的值
int num = getValue(s.charAt(i));
// 如果前一个字符的值小于当前字符的值,表示需要减去前一个值
if (preNum < num) {
// 从 sum 中减去前一个字符的值
sum = sum - preNum;
} else {
// 否则,将前一个字符的值加到 sum 中
sum = sum + preNum;
}
// 更新前一个字符的值为当前字符的值
preNum = num;
}
// 将最后一个字符的值加到 sum 中
sum = sum + preNum;
// 返回转换后的整数值
return sum;
}
// 辅助方法:将罗马数字字符转换为对应的整数值
private int getValue(char ch) {
switch(ch) {
case 'I':
return 1;
case 'V':
return 5;
case 'X':
return 10;
case 'L':
return 50;
case 'C':
return 100;
case 'D':
return 500;
case 'M':
return 1000;
default:
return 0;
}
}
}
class Solution {
public String intToRoman(int num) {
// 定义罗马数字和对应的整数值
int[] values = {1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1};
String[] symbals = {"M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"};
// 创建一个可变的字符串缓冲区用于存储生成的罗马数字
StringBuilder sb = new StringBuilder();
// 遍历整数值数组
for (int i = 0; i < values.length; i++) {
// 当输入的整数 num 大于等于当前整数值时
while(values[i] <= num) {
// 将对应的罗马数字符号添加到结果字符串缓冲区中
sb.append(symbals[i]);
// 从 num 中减去当前整数值
num = num - values[i];
}
// 如果 num 变为 0,表示已经转换完成,退出循环
if (num == 0) {
break;
}
}
// 将字符串缓冲区转换为字符串并返回
return sb.toString();
}
}
class Solution {
// 方法:计算字符串中最后一个单词的长度
public int lengthOfLastWord(String s) {
// "the moon "
// 去除字符串两端的空白字符
s = s.trim();
// 通过总长度减去最后一个空格的索引来计算最后一个单词的长度
// s.length() - 1 是为了得到最后一个字符的索引
// s.lastIndexOf(" ") 返回最后一个空格的索引
return s.length() - 1 - s.lastIndexOf(" ");
}
}
class Solution {
// 方法:找到字符串数组中最长的公共前缀
public String longestCommonPrefix(String[] strs) {
// ["flower","flow","flight"]
// 如果数组为空,返回空字符串
if (strs.length == 0) {
return "";
}
System.out.println(Arrays.toString(strs));
// 对字符串数组进行排序,以便之后容易找到公共前缀,因为排序后相同前缀的字符串会相邻
Arrays.sort(strs);
// 获取排序后的第一个字符串
String start = strs[0];
// 获取排序后的最后一个字符串
String end = strs[strs.length - 1];
// 计算这两个字符串的最小长度,以防止访问超出范围
int num = Math.min(start.length(), end.length());
int result = 0;
// 逐个字符比较第一个和最后一个字符串,直到不同字符或达到最小长度为止
for (int i = 0; i < num && start.charAt(i) == end.charAt(i); i++) {
result = result + 1;
}
// 使用 substring 方法返回从第一个字符串开始到位置 result 的子字符串,即最长的公共前缀
return start.substring(0, result);
}
}
class Solution {
public String reverseWords(String s) {
// 除去开头和末尾的空白字符
s = s.trim();
// 正则匹配连续的空白字符作为分隔符分割
List<String> list = Arrays.asList(s.split("\\s+"));
System.out.println(list);
// 列表反正
Collections.reverse(list);
// 使用join拼接
return String.join(" ", list);
}
}
class Solution {
public String convert(String s, int numRows) {
// 字符串长度
int n = s.length();
// 行数
int r = numRows;
// 如果行数为 1 或者行数大于等于字符串长度,直接返回原字符串
if (r == 1 || numRows >= n) {
return s;
}
// 计算周期长度
int t = r * 2 - 2;
// 计算二维数组的列数
int c = (n + t - 1) / t * (r - 1);
// 创建二维字符数组
char[][] mat = new char[r][c];
// 遍历字符串中的每个字符
for (int i = 0, x = 0, y = 0; i < n; i++) {
// 将当前字符放入二维数组中
mat[x][y] = s.charAt(i);
// 如果当前位置在周期的前半部分,向下移动
if (i % t < r - 1) {
x++;
} else {
// 如果在周期的后半部分,向右上移动
x--;
y++;
}
}
// 创建字符串缓冲区用于存储结果
StringBuilder sb = new StringBuilder();
// 遍历二维数组的每一行
for (int i = 0; i < mat.length; i++) {
// 遍历每一行中的每个字符
for (int j = 0; j < mat[i].length; j++) {
// 如果字符不为空,将其添加到结果字符串缓冲区中
if (mat[i][j] != 0) {
sb.append(mat[i][j]);
}
}
}
// 将字符串缓冲区转换为字符串并返回
return sb.toString();
}
}
class Solution {
// 方法:在主字符串 haystack 中查找子字符串 needle
public int strStr(String haystack, String needle) {
// 获取主字符串 haystack 的长度
int n = haystack.length();
// 获取子字符串 needle 的长度
int m = needle.length();
// 遍历 haystack,直到剩余字符不足以容纳 needle
for (int i = 0; i <= n - m; i++) {
// 初始化标志,表示当前字符匹配
boolean flag = true;
// 遍历 needle 的每个字符,检查是否与 haystack 的当前子串匹配
for (int j = 0; j < m; j++) {
// 如果当前字符不匹配
if (haystack.charAt(i + j) != needle.charAt(j)) {
// 设置标志为 false,表示不匹配
flag = false;
// 跳出内层循环
break;
}
}
// 如果所有字符匹配,即 flag 仍为 true
if (flag) {
// 返回当前起始索引 i
return i;
}
}
// 如果没有找到 needle,返回 -1
return -1;
}
}