Java详解LeetCode 热题 100(15):LeetCode 189. 轮转数组(Rotate Array)详解

文章目录

    • 1. 题目描述
    • 2. 理解题目
    • 3. 解法一:使用额外数组
      • 3.1 思路
      • 3.2 Java代码实现
      • 3.3 代码详解
      • 3.4 复杂度分析
      • 3.5 适用场景
    • 4. 解法二:环状替换法(原地算法)
      • 4.1 思路
      • 4.2 Java代码实现
      • 4.3 代码详解
      • 4.4 复杂度分析
      • 4.5 陷阱与注意事项
    • 5. 解法三:数组翻转法(最优原地算法)
      • 5.1 思路
      • 5.2 Java代码实现
      • 5.3 代码详解
      • 5.4 数学证明
      • 5.5 复杂度分析
      • 5.6 适用场景
    • 6. 详细步骤分析与示例跟踪
      • 6.1 示例跟踪:使用额外数组法
      • 6.2 示例跟踪:环状替换法
      • 6.3 示例跟踪:数组翻转法
    • 7. 常见错误与优化
      • 7.1 常见错误
      • 7.2 优化技巧
    • 8. 三种解法的对比与选择
    • 9. 扩展题目与应用
      • 9.1. 左轮转数组
      • 9.2. 字符串轮转
      • 9.3. 循环移位操作
    • 10. 实际应用场景
    • 11. 完整的 Java 解决方案
    • 12. 总结与技巧
      • 12.1 解题要点
      • 12.2 学习收获
      • 12.3 面试技巧
    • 13. 参考资料

1. 题目描述

给你一个数组,将数组中的元素向右轮转 k 个位置,其中 k 是非负数。

示例 1:

输入: nums = [1,2,3,4,5,6,7], k = 3
输出: [5,6,7,1,2,3,4]
解释:
向右轮转 1 步: [7,1,2,3,4,5,6]
向右轮转 2 步: [6,7,1,2,3,4,5]
向右轮转 3 步: [5,6,7,1,2,3,4]

示例 2:

输入:nums = [-1,-100,3,99], k = 2
输出:[3,99,-1,-100]
解释: 
向右轮转 1 步: [99,-1,-100,3]
向右轮转 2 步: [3,99,-1,-100]

提示:

  • 1 <= nums.length <= 10^5
  • -2^31 <= nums[i] <= 2^31 - 1
  • 0 <= k <= 10^5

进阶:

  • 尽可能想出更多的解决方案,至少有三种不同的方法可以解决这个问题。
  • 你可以使用空间复杂度为 O(1) 的 原地 算法解决这个问题吗?

2. 理解题目

这道题要求我们将数组中的所有元素向右移动k个位置。具体来说:

  • 数组中的每个元素都向右移动k个索引位置
  • 数组是"循环"的,即超出数组末尾的元素会被放置到数组的开头
  • 我们需要原地修改数组,而不是创建一个新数组(尽管也可以使用额外空间的解法)

关键点:

  1. k可能大于数组长度,因此实际的移动次数是k % n(其中n是数组长度)
  2. 向右轮转k次等同于将数组最后k个元素移动到数组开头
  3. 这道题可以有多种解法,包括使用额外空间和原地(O(1)空间复杂度)算法

3. 解法一:使用额外数组

3.1 思路

最简单直观的方法是创建一个新数组,然后将原数组的每个元素放到新数组中的正确位置:

  1. 创建一个与原数组相同大小的新数组
  2. 对于原数组中索引为i的元素,其在新数组中的位置为(i + k) % n
  3. 将新数组的内容复制回原数组

这种方法使用了O(n)的额外空间,但思路非常清晰,适合初学者理解。

3.2 Java代码实现

class Solution {public void rotate(int[] nums, int k) {int n = nums.length;// 处理 k 大于数组长度的情况k = k % n;// 如果k为0,不需要轮转if (k == 0) {return;}// 创建一个新数组来存储轮转后的结果int[] result = new int[n];// 将原数组中的元素放入新数组的正确位置for (int i = 0; i < n; i++) {result[(i + k) % n] = nums[i];}// 将新数组的内容复制回原数组for (int i = 0; i < n; i++) {nums[i] = result[i];}}
}

3.3 代码详解

详细解释每一步的意义和实现:

int n = nums.length;// 处理 k 大于数组长度的情况
k = k % n;// 如果k为0,不需要轮转
if (k == 0) {return;
}
  • 首先获取数组长度n
  • 由于轮转n次会回到原始状态,所以我们只需要考虑k % n次轮转
  • 如果k为0或者k是n的倍数,数组不需要变化,直接返回
// 创建一个新数组来存储轮转后的结果
int[] result = new int[n];// 将原数组中的元素放入新数组的正确位置
for (int i = 0; i < n; i++) {result[(i + k) % n] = nums[i];
}
  • 创建一个与原数组相同大小的新数组
  • 将原数组中索引为i的元素放到新数组中索引为(i + k) % n的位置
  • 这里使用模运算是为了处理索引超出数组长度的情况
// 将新数组的内容复制回原数组
for (int i = 0; i < n; i++) {nums[i] = result[i];
}
  • 最后,将临时数组中的结果复制回原数组,完成轮转操作

3.4 复杂度分析

  • 时间复杂度: O(n),其中n是数组的长度。我们需要遍历数组两次,每次遍历的时间复杂度是O(n)。
  • 空间复杂度: O(n),我们创建了一个与原数组等长的新数组。

3.5 适用场景

这种解法适用于:

  • 初学者理解问题
  • 代码简洁性优先于空间效率的场景
  • 数组不太大的情况

4. 解法二:环状替换法(原地算法)

4.1 思路

我们可以直接在原数组上进行操作,不使用额外空间。基本思想是:

  1. 从位置0开始,将当前位置的元素放到它应该去的位置(即(i + k) % n),同时记录被替换的元素
  2. 然后将被替换的元素放到它应该去的位置,继续这个过程
  3. 当我们回到起始位置时,我们已经完成了一个循环,需要从下一个位置开始新的循环
  4. 重复这个过程,直到所有元素都被访问

这种方法不使用额外数组,但需要仔细处理访问元素的顺序。

4.2 Java代码实现

class Solution {public void rotate(int[] nums, int k) {int n = nums.length;k = k % n;// 如果k为0,不需要轮转if (k == 0) {return;}int count = 0; // 记录已经移动的元素数量// 从0开始,最多需要处理n个元素for (int start = 0; count < n; start++) {int current = start; // 当前处理的位置int prev = nums[start]; // 当前位置的值do {// 计算下一个位置int next = (current + k) % n;// 保存下一个位置的值int temp = nums[next];// 将当前值放到下一个位置nums[next] = prev;// 更新current和prev,继续下一次替换current = next;prev = temp;count++;} while (start != current); // 当回到起始位置时,一个循环结束}}
}

4.3 代码详解

环状替换的关键在于追踪元素的移动路径,确保每个元素都被移动到正确位置:

int count = 0; // 记录已经移动的元素数量// 从0开始,最多需要处理n个元素
for (int start = 0; count < n; start++) {int current = start; // 当前处理的位置int prev = nums[start]; // 当前位置的值
  • count变量记录我们已经处理过的元素数量
  • start表示当前循环的起始位置
  • current跟踪我们当前正在处理的位置
  • prev存储当前位置原来的值
do {// 计算下一个位置int next = (current + k) % n;// 保存下一个位置的值int temp = nums[next];// 将当前值放到下一个位置nums[next] = prev;// 更新current和prev,继续下一次替换current = next;prev = temp;count++;
} while (start != current); // 当回到起始位置时,一个循环结束
  • 计算元素应该被放置的下一个位置:(current + k) % n
  • 在替换前,保存目标位置的原始值
  • 将当前值放到目标位置
  • 更新current为新位置,prev为新位置原来的值
  • 增加已处理元素计数
  • 重复此过程,直到回到循环的起始位置

当一个循环结束(回到起始位置)时,可能还有未被访问的元素。因此,我们增加start并开始一个新的循环,直到所有元素都被处理。

4.4 复杂度分析

  • 时间复杂度: O(n),每个元素只会被移动一次,总共需要移动n次。
  • 空间复杂度: O(1),只使用了有限的几个变量,不需要额外数组。

4.5 陷阱与注意事项

环状替换法需要特别注意:

  1. 处理循环长度:如果k和n有公约数,一个循环结束后可能还有元素未被访问,需要开始新的循环
  2. 边界条件:确保我们处理了所有的元素(通过计数)
  3. 避免原地自我覆盖:在移动元素前保存下一个位置的值

5. 解法三:数组翻转法(最优原地算法)

5.1 思路

这是最优雅且高效的解法。基本思想是:

  1. 首先翻转整个数组
  2. 然后翻转前k个元素
  3. 最后翻转剩余的n-k个元素

这种方法不需要额外空间,操作简单明了,且易于实现。

5.2 Java代码实现

class Solution {public void rotate(int[] nums, int k) {int n = nums.length;k = k % n;// 如果k为0,不需要轮转if (k == 0) {return;}// 1. 翻转整个数组reverse(nums, 0, n - 1);// 2. 翻转前k个元素reverse(nums, 0, k - 1);// 3. 翻转剩余的n-k个元素reverse(nums, k, n - 1);}// 辅助函数:翻转数组的指定部分private void reverse(int[] nums, int start, int end) {while (start < end) {int temp = nums[start];nums[start] = nums[end];nums[end] = temp;start++;end--;}}
}

5.3 代码详解

数组翻转法的优雅之处在于它非常直观:

// 1. 翻转整个数组
reverse(nums, 0, n - 1);
  • 首先将整个数组翻转,这样原来的顺序就变成了逆序
  • 例如:[1,2,3,4,5,6,7] 变成 [7,6,5,4,3,2,1]
// 2. 翻转前k个元素
reverse(nums, 0, k - 1);
  • 然后翻转前k个元素,将这部分恢复正确的相对顺序
  • 对于k=3,[7,6,5,4,3,2,1] 的前k个元素 [7,6,5] 翻转后变成 [5,6,7,4,3,2,1]
// 3. 翻转剩余的n-k个元素
reverse(nums, k, n - 1);
  • 最后翻转剩余的n-k个元素,将这部分也恢复正确的相对顺序
  • [5,6,7,4,3,2,1] 的后n-k个元素 [4,3,2,1] 翻转后变成 [5,6,7,1,2,3,4]
  • 这就是最终的轮转结果
// 辅助函数:翻转数组的指定部分
private void reverse(int[] nums, int start, int end) {while (start < end) {int temp = nums[start];nums[start] = nums[end];nums[end] = temp;start++;end--;}
}
  • 辅助函数实现了数组特定范围内的翻转
  • 使用双指针法,从两端向中间逐步交换元素
  • 这是一个标准的数组翻转操作

5.4 数学证明

为什么数组翻转法能实现轮转效果?我们可以从数学角度证明:

设原数组为A,长度为n,需要右移k个位置。

  1. 定义A’ = A[0…n-k-1],表示原数组的前n-k个元素
  2. 定义A’’ = A[n-k…n-1],表示原数组的后k个元素
  3. 原数组可表示为:A = [A’, A’']
  4. 向右轮转k个位置后的数组为:B = [A’‘, A’]

数组翻转法的步骤:

  1. 翻转整个数组:[A’, A’‘] → [(A’‘)^r, (A’)r],其中r表示翻转
  2. 翻转前k个元素:[(A’‘)^r, (A’)^r] → [A’‘, (A’)^r]
  3. 翻转后n-k个元素:[A’‘, (A’)^r] → [A’‘, A’]

最终结果:[A’‘, A’],这正是轮转后的结果。

5.5 复杂度分析

  • 时间复杂度: O(n),翻转数组需要O(n)的时间。
  • 空间复杂度: O(1),只使用了有限的临时变量。

5.6 适用场景

数组翻转法因其简洁性和效率,几乎适用于所有场景:

  • 需要原地操作的场景
  • 性能要求高的场景
  • 代码简洁度要求高的场景

6. 详细步骤分析与示例跟踪

让我们通过一个具体例子来跟踪每种算法的执行过程,加深理解。

6.1 示例跟踪:使用额外数组法

输入:nums = [1,2,3,4,5,6,7], k = 3

  1. 计算实际轮转次数:k = k % n = 3 % 7 = 3
  2. 创建新数组:result = new int[7]
  3. 将原数组元素放入新数组:
    • nums[0]=1 → result[(0+3)%7]=result[3]=1
    • nums[1]=2 → result[(1+3)%7]=result[4]=2
    • nums[2]=3 → result[(2+3)%7]=result[5]=3
    • nums[3]=4 → result[(3+3)%7]=result[6]=4
    • nums[4]=5 → result[(4+3)%7]=result[0]=5
    • nums[5]=6 → result[(5+3)%7]=result[1]=6
    • nums[6]=7 → result[(6+3)%7]=result[2]=7
  4. 现在result=[5,6,7,1,2,3,4]
  5. 将result复制回nums:nums=[5,6,7,1,2,3,4]

6.2 示例跟踪:环状替换法

输入:nums = [1,2,3,4,5,6,7], k = 3

  1. 计算实际轮转次数:k = k % n = 3 % 7 = 3

  2. 开始从start=0处的环状替换:

    • 当前位置current=0,当前值prev=nums[0]=1
    • 下一个位置next=(0+3)%7=3,保存nums[3]=4
    • 将1放入位置3:nums=[1,2,3,1,5,6,7],current=3,prev=4
    • 下一个位置next=(3+3)%7=6,保存nums[6]=7
    • 将4放入位置6:nums=[1,2,3,1,5,6,4],current=6,prev=7
    • 下一个位置next=(6+3)%7=2,保存nums[2]=3
    • 将7放入位置2:nums=[1,2,7,1,5,6,4],current=2,prev=3
    • 下一个位置next=(2+3)%7=5,保存nums[5]=6
    • 将3放入位置5:nums=[1,2,7,1,5,3,4],current=5,prev=6
    • 下一个位置next=(5+3)%7=1,保存nums[1]=2
    • 将6放入位置1:nums=[1,6,7,1,5,3,4],current=1,prev=2
    • 下一个位置next=(1+3)%7=4,保存nums[4]=5
    • 将2放入位置4:nums=[1,6,7,1,2,3,4],current=4,prev=5
    • 下一个位置next=(4+3)%7=0,保存nums[0]=1
    • 将5放入位置0:nums=[5,6,7,1,2,3,4],current=0,prev=1
    • 现在current=0=start,一个循环结束,且count=7,所有元素都已处理
  3. 最终结果:nums=[5,6,7,1,2,3,4]

6.3 示例跟踪:数组翻转法

输入:nums = [1,2,3,4,5,6,7], k = 3

  1. 计算实际轮转次数:k = k % n = 3 % 7 = 3
  2. 翻转整个数组:
    • nums=[1,2,3,4,5,6,7] → nums=[7,6,5,4,3,2,1]
  3. 翻转前k个元素(前3个):
    • nums=[7,6,5,4,3,2,1] → nums=[5,6,7,4,3,2,1]
  4. 翻转剩余n-k个元素(后4个):
    • nums=[5,6,7,4,3,2,1] → nums=[5,6,7,1,2,3,4]
  5. 最终结果:nums=[5,6,7,1,2,3,4]

7. 常见错误与优化

7.1 常见错误

  1. 忘记处理k大于数组长度的情况

    // 错误:不处理k大于数组长度的情况
    public void rotate(int[] nums, int k) {// k可能大于nums.length,未处理会导致索引越界...
    }// 正确:进行取模操作
    public void rotate(int[] nums, int k) {int n = nums.length;k = k % n; // 确保k在有效范围内...
    }
    
  2. 环状替换中的循环处理错误

    // 错误:处理不完整,可能漏掉某些元素
    public void rotate(int[] nums, int k) {// ...int start = 0;int current = start;int prev = nums[start];// 只进行一个循环,可能无法处理所有元素do {// ...} while (start != current);
    }// 正确:确保处理所有元素
    public void rotate(int[] nums, int k) {// ...int count = 0;for (int start = 0; count < n; start++) {// 确保所有元素都被处理// ...count++;}
    }
    
  3. 数组翻转边界错误

    // 错误:翻转边界不正确
    reverse(nums, 0, k); // 错误,应该是k-1
    reverse(nums, k, n); // 错误,应该是k到n-1// 正确:正确的翻转边界
    reverse(nums, 0, k - 1);
    reverse(nums, k, n - 1);
    

7.2 优化技巧

  1. 提前检查特殊情况

    // 优化:提前处理不需要轮转的情况
    if (k == 0 || k % n == 0) {return; // 不需要轮转
    }
    
  2. 使用Java内置的数组复制方法

    // 优化:使用System.arraycopy替代手动循环复制
    System.arraycopy(result, 0, nums, 0, n);
    
  3. 减少不必要的取模操作

    // 优化前:每次都进行取模
    for (int i = 0; i < n; i++) {result[(i + k) % n] = nums[i];
    }// 优化后:预计算起始位置
    int start = n - k;
    for (int i = 0; i < k; i++) {result[i] = nums[start + i];
    }
    for (int i = 0; i < n - k; i++) {result[k + i] = nums[i];
    }
    
  4. 环状替换中优化循环判断

    // 优化:使用数学方法计算循环次数
    int gcd = gcd(n, k); // 计算n和k的最大公约数// 只需要进行gcd次循环,每次处理n/gcd个元素
    for (int start = 0; start < gcd; start++) {// ...
    }// 辅助方法:计算最大公约数
    private int gcd(int a, int b) {return b == 0 ? a : gcd(b, a % b);
    }
    

8. 三种解法的对比与选择

解法时间复杂度空间复杂度优点缺点适用场景
额外数组法O(n)O(n)简单直观,容易实现需要额外空间初学者,空间不敏感的场景
环状替换法O(n)O(1)不需要额外空间实现较复杂,需要处理循环空间敏感场景,追求原地操作
数组翻转法O(n)O(1)优雅简洁,不需要额外空间需要理解翻转原理几乎所有场景的最优选择

总结

  • 如果你是初学者或追求代码简洁性,使用额外数组法
  • 如果你需要节省空间且追求性能,使用数组翻转法
  • 环状替换法虽然有趣,但实现复杂,通常不是首选

9. 扩展题目与应用

9.1. 左轮转数组

与本题类似,但方向相反,将数组元素向左移动k个位置。

解决方案:

  • 向左轮转k个位置等同于向右轮转n-k个位置
  • 或者使用相同的数组翻转法,只需调整翻转顺序:
    1. 翻转整个数组
    2. 翻转前n-k个元素
    3. 翻转后k个元素

9.2. 字符串轮转

LeetCode 796. 旋转字符串:检查一个字符串是否可以通过多次轮转变成另一个字符串。

解决思路:将原字符串与自身拼接,如果目标字符串是拼接结果的子串,则可以通过轮转得到。

9.3. 循环移位操作

在计算机系统中,轮转操作常用于循环移位(Circular Shift):

  • 循环左移:将二进制数的最高位移到最低位
  • 循环右移:将二进制数的最低位移到最高位

10. 实际应用场景

轮转数组在实际编程中有多种应用:

  1. 缓冲区管理

    • 实现循环缓冲区时,可以使用轮转数组避免数据移动
    • 在流媒体处理中保持最近的数据片段
  2. 图像处理

    • 图像旋转和变换
    • 图像滤波器的实现
  3. 信号处理

    • 信号采样和处理时的数据轮转
    • FFT算法中的数据重排
  4. 游戏开发

    • 游戏地图的循环移动(如无限地图)
    • 轮流游戏中的玩家顺序管理
  5. 调度算法

    • 轮转调度算法(Round Robin)中任务的轮换
    • 分时系统中的时间片分配

11. 完整的 Java 解决方案

以下是结合了各种最佳实践的最优解法(数组翻转法):

class Solution {public void rotate(int[] nums, int k) {if (nums == null || nums.length <= 1) {return; // 处理边界情况}int n = nums.length;k = k % n; // 处理k大于数组长度的情况if (k == 0) {return; // 不需要轮转}// 三步翻转法reverse(nums, 0, n - 1);   // 翻转整个数组reverse(nums, 0, k - 1);   // 翻转前k个元素reverse(nums, k, n - 1);   // 翻转剩余的n-k个元素}// 翻转数组的指定范围private void reverse(int[] nums, int start, int end) {while (start < end) {int temp = nums[start];nums[start++] = nums[end];nums[end--] = temp;}}
}

这个解法简洁高效,适用于大多数场景。在LeetCode上,这个解法通常能击败95%以上的提交。

12. 总结与技巧

12.1 解题要点

  1. 正确理解轮转:理解轮转的本质是循环移动,超出数组末尾的元素会回到开头。
  2. 取模处理:使用k % n来处理k可能大于数组长度的情况。
  3. 选择合适的算法:根据空间要求选择适当的算法(额外空间法或原地算法)。
  4. 翻转技巧:数组翻转是解决轮转问题的强大工具。

12.2 学习收获

通过学习轮转数组问题,你可以掌握:

  • 原地算法的思想和实现
  • 双指针技术在数组操作中的应用
  • 数学思维在算法设计中的重要性
  • 空间和时间复杂度的权衡

12.3 面试技巧

如果在面试中遇到此类问题:

  1. 先提出最简单的解法(使用额外数组)
  2. 然后提出原地算法(如数组翻转法)
  3. 讨论每种方法的时间和空间复杂度
  4. 分析各种解法的适用场景和优缺点
  5. 实现你认为最优的解法

记住,展示你的思考过程和对不同解法的理解,比仅仅给出一个正确答案更重要。

13. 参考资料

  • LeetCode 官方题解:轮转数组
  • LeetCode 题目链接:轮转数组

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/80649.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数据治理域——日志数据采集设计

摘要 本文主要介绍了Web页面端日志采集的设计。首先阐述了页面浏览日志采集&#xff0c;包括客户端日志采集的实现方式、采集内容及技术亮点。接着介绍了无线客户端端日志采集&#xff0c;包括UserTrack的核心设计、移动端与浏览器端采集差异以及典型应用场景崩溃分析。最后探…

PYTHON训练营DAY24

# SO代码我们的感情好像跳楼机 # 元组创建时&#xff0c;可以省略括号&#xff1a;my_tuple4 10, 20, thirty # 字符串要加“ ” 元组 一、创建 my_tuple1 (1, 2, 3) my_tuple2 (a, b, c) my_tuple3 (1, hello, 3.14, [4, 5]) # 可以包含不同类型的元素 print(my_tupl…

超声波传感器模块

欢迎来到 破晓的历程的 博客 ⛺️不负时光&#xff0c;不负己✈️ 文章目录 1.HC-SR04介绍2.HC-SR04原理介绍2.1原理概述3.2原理详解 4驱动代码编写4.1写前思考4.2硬件连线 5.总结hcsr04.hhcsr04.c 1.HC-SR04介绍 超声波传感器有很多种类的型号&#xff1a;HC-SR04、UC-025、…

《Effective Python》第2章 字符串和切片操作——深入理解Python 中的字符数据类型(bytes 与 str)的差异

引言 本篇博客基于学习《Effective Python》第三版 Chapter 2: Strings and Slicing 中的 Item 10: Know the Differences Between bytes and str 的总结与延伸。在 Python 编程中&#xff0c;字符串处理是几乎每个开发者都会频繁接触的基础操作。然而&#xff0c;Python 中的…

py7zr解压文件时报错CrcError(crc32, f.crc32, f.filename)

报错信息 Traceback (most recent call last):File "/home/hp/project/test/file_util.py", line 130, in extract_archive_7zarchive.extract(targets[fixed_file], pathoutput_dir, recursiveTrue)File "/home/hp/miniconda3/envs/celery/lib/python3.10/sit…

物理:由基本粒子组成的个体能否提炼和重组?

个体差异源于基本粒子组合的复杂性与随机性,这一假设若成立,确实可能为生物医学带来革命性突破——但需要突破技术、理论与系统层级的多重壁垒。以下从科学逻辑与技术路径展开分析: 一、随机组合中的共性与稳定结构 1. 自然界的自组织规律 涌现性(Emergence):尽管粒子组…

动态路由EIGRP的配置

动态路由EIGRP的配置 动态路由EIGRP&#xff1a;增强内部网关协议 为何收敛快、不成环&#xff1f; 路由计算的无环路和路由的收敛速度是路由计算的重要指标。EIGRP协议由于使用了DUAL算法&#xff0c;使得EIGRP协议在路由计算中不可能有环路路由产生&#xff0c;同时路由计…

组合问题(多条件)

39. 组合总和 - 力扣&#xff08;LeetCode&#xff09; class Solution { private:vector<vector<int>>result;vector<int>path;void backtracking(vector<int>& candidates, int target,int sum,int startIndex){if(sum>target){return;}if(…

SimScape物理建模实例2--带控制的单质量弹簧阻尼系统

模型下载&#xff1a; 基于simscape&#xff0c;单质量系统带位置控制资源-CSDN文库 在实例1中&#xff0c;我们搭建了不带控制的单质量弹簧阻尼系统&#xff0c;该系统没有外界力量介入&#xff0c;只有弹簧的初始弹力&#xff0c;带着弹簧使劲弹来弹去。 SimScape物理建模实…

OpenAI Text 模型与 Chat 模型调用实战指南:从基础配置到创意花店命名

在 AI 应用开发的浪潮中&#xff0c;OpenAI 的大语言模型成为开发者实现创新功能的得力工具。其中&#xff0c;Text 模型和 Chat 模型作为核心接口&#xff0c;被广泛应用于文本生成、对话交互等场景。本文将以 “为花店起名” 为实际需求&#xff0c;手把手教你如何安全调用这…

网页常见水印实现方式

文章目录 1 明水印技术实现1.1 DOM覆盖方案1.2 Canvas动态渲染1.3 CSS伪元素方案2 暗水印技术解析2.1 空域LSB算法2.2 频域傅里叶变换3 防篡改机制设计3.1 MutationObserver防护3.2 Canvas指纹追踪4 前后端实现对比5 攻防博弈深度分析5.1 常见破解手段5.2 进阶防御策略6 选型近…

现代化QML组件开发教程

现代化QML组件开发教程 目录 QML基础介绍QML项目结构基本组件详解自定义组件开发状态与过渡高级主题最佳实践 QML基础介绍 什么是QML QML (Qt Meta Language) 是一种声明式语言&#xff0c;专为用户界面设计而创建。它是Qt框架的一部分&#xff0c;让开发者能够创建流畅、…

C/C++ 程序执行的主要过程

预处理&#xff08;Preprocessing&#xff09; 任务&#xff1a; 处理源代码中以 # 开头的预处理指令&#xff0c;包括&#xff1a; 头文件包含&#xff08;#include&#xff09;&#xff1a;将头文件&#xff08;如 stdio.h&#xff09;的内容直接插入到源文件中。宏替换&…

时间序列预测建模的完整流程以及数据分析【学习记录】

文章目录 1.时间序列建模的完整流程2. 模型选取的和数据集2.1.ARIMA模型2.2.数据集介绍 3.时间序列建模3.1.数据获取3.2.处理数据中的异常值3.2.1.Nan值3.2.2.异常值的检测和处理&#xff08;Z-Score方法&#xff09; 3.3.离散度3.4.Z-Score3.4.1.概述3.4.2.公式3.4.3.Z-Score与…

ValueError: Caught ValueError in DataLoader worker process 0.

参考链接&#xff1a; https://stackoverflow.com/questions/1841565/valueerror-invalid-literal-for-int-with-base-10 它提示我有个地方值错误空字符 果然因为格式处理没有传进去东西&#xff0c;找下原因&#xff0c;让它正常处理 原来是相对路径的.影响了程序运行 将v…

JavaScript性能优化实战,从理论到落地的全面指南

在前端开发领域&#xff0c;JavaScript的性能优化是提升用户体验的核心环节。随着Web应用复杂度的提升&#xff0c;开发者面临的性能瓶颈也日益多样化。本文将从理论分析、代码实践和工具使用三个维度&#xff0c;系统性地讲解JavaScript性能优化的实战技巧&#xff0c;并通过大…

SQL、Oracle 和 SQL Server 的比较与分析

SQL、Oracle 和 SQL Server 的比较与分析 一、基础概念 1. SQL (Structured Query Language) 定义&#xff1a;结构化查询语言&#xff0c;用于管理关系型数据库的标准语言类型&#xff1a; DDL (数据定义语言)&#xff1a;CREATE, ALTER, DROPDML (数据操作语言)&#xff1…

Telnet 类图解析

Telnet 类图&#xff08;文本描述&#xff09; --------------------------------------- | Telnet | --------------------------------------- | - host: str | # 目标主机 | - port: int …

Ansible安装与核心模块实战指南

Ansible安装与核心模块实战指南 自动化运维入门:从安装到模块化任务配置 Ansible作为一款无代理自动化工具,通过模块化设计实现高效管理,尤其适用于快速部署、配置和维护大规模系统。本文将从安装、核心模块使用到实际案例,全面解析其核心功能与最佳实践。 一、Ansible安装…

VLLM推理大模型显存不够后,导致程序引擎崩溃的调优方案尝试

背景介绍 硬件 A800 80G模型 chat-glm4-9b-128K环境 生产正常显存占用情况 glm4 占用32GB 其他显存工占用38GB左右 总共剩余10GB。 问题描述 推理时报错日志&#xff0c;由于内网环境无法拿出日志&#xff0c;与下面的类似。 File "/data/miniconda3_new/envs/vllm-new…