当前位置: 首页 > news >正文

java学习 leetcode31 下一个排列

1.排列方法(按照全排列,数组,整数来回转换的思路)

package com.hmdp.leetcode;import java.util.*;
public class backtracking31 {public void nextPermutation(int[] nums) {// 1. 将当前数组转为字符串表示StringBuilder sb = new StringBuilder();for (int num : nums) {sb.append(num);}String value = sb.toString();// 2. 生成所有全排列,并存储为字符串Set<String> result = new HashSet<>();boolean[] used = new boolean[nums.length];backtrack(nums, new StringBuilder(), used, result);// 3. 排序所有排列List<String> sortedList = new ArrayList<>(result);Collections.sort(sortedList);// 4. 找到当前 value 的下一个排列for (int j = 0; j < sortedList.size(); j++) {if (sortedList.get(j).equals(value)) {int nextIndex = (j == sortedList.size() - 1) ? 0 : j + 1;String nextValue = sortedList.get(nextIndex);// 5. 写回原数组Arrays.fill(nums, 0);for (int k = 0; k < nextValue.length(); k++) {nums[k] = nextValue.charAt(k) - '0';}break;}}}// 回溯生成全排列(字符串形式)private void backtrack(int[] nums, StringBuilder path, boolean[] used, Set<String> result) {if (path.length() == nums.length) {result.add(path.toString());return;}for (int i = 0; i < nums.length; i++) {if (used[i]) continue;used[i] = true;path.append(nums[i]);backtrack(nums, path, used, result);path.deleteCharAt(path.length() - 1);used[i] = false;}}}

 2.测试用例


import com.hmdp.leetcode.backtracking31;
import org.junit.jupiter.api.Test;import static org.junit.jupiter.api.Assertions.*;import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;public class SolutionTest {@Testpublic void testNextPermutation() {backtracking31 solution = new backtracking31();// Existing test casesint[] nums1 = {1, 2, 3};solution.nextPermutation(nums1);assertArrayEquals(new int[]{1, 3, 2}, nums1);int[] nums2 = {3, 2, 1};solution.nextPermutation(nums2);assertArrayEquals(new int[]{1, 2, 3}, nums2);int[] nums3 = {1, 1, 5};solution.nextPermutation(nums3);assertArrayEquals(new int[]{1, 5, 1}, nums3);int[] nums4 = {0, 0};solution.nextPermutation(nums4);assertArrayEquals(new int[]{0, 0}, nums4);int[] nums5 = {2, 2, 2};solution.nextPermutation(nums5);assertArrayEquals(new int[]{2, 2, 2}, nums5);int[] nums6 = {1, 3, 4, 2};solution.nextPermutation(nums6);assertArrayEquals(new int[]{1, 4, 2, 3}, nums6);int[] nums7 = {4, 3, 2, 1};solution.nextPermutation(nums7);assertArrayEquals(new int[]{1, 2, 3, 4}, nums7);int[] nums8 = {1, 1, 1, 1};solution.nextPermutation(nums8);assertArrayEquals(new int[]{1, 1, 1, 1}, nums8);int[] nums9 = {1, 2, 4, 3};solution.nextPermutation(nums9);assertArrayEquals(new int[]{1, 3, 2, 4}, nums9);// New test casesint[] nums10 = {0, 0, 4, 2, 1, 0};solution.nextPermutation(nums10);assertArrayEquals(new int[]{0, 1, 0, 0, 2, 4}, nums10);int[] nums11 = {6, 7, 5, 3, 5, 6, 2, 9, 1, 2, 7, 0, 9};solution.nextPermutation(nums11);assertArrayEquals(new int[]{6, 7, 5, 3, 5, 6, 2, 9, 1, 2, 9, 0, 7}, nums11);}
}

最后一个测试用例超时了,其他都是对的,就是思路好理解些

1. 溢出

✅ 问题原因:
  • 当排列中的数字较大或排列长度较长时,直接使用整数类型(如 intlong)来表示排列可能会导致数值溢出。

  • 例如,在某些情况下,排列可能需要非常大的数值范围,而标准的整数类型无法容纳。

✅ 修复方式:
  • 改用 String 表示排列:字符串可以表示任意长度和大小的排列,不会受到数值类型的限制。通过字符串处理,你可以避免数值溢出的问题。


2. 前导零丢失(这个确实有)

✅ 问题原因:
  • 在使用整数类型表示排列时,前导零会被自动忽略。例如,排列 [0, 0, 4, 2, 1, 0] 转换为整数后会变成 4210,丢失了前导零。

  • 这会导致排列信息不完整,影响后续的排列生成和比较。

✅ 修复方式:
  • 使用字符串处理,保留完整信息:字符串可以保留排列中的所有数字,包括前导零。通过字符串操作,你可以确保排列的完整性,避免前导零丢失的问题。


3. 效率低

✅ 问题原因:
  • 使用回溯法或其他复杂算法生成全排列时,时间复杂度较高,尤其是在大规模输入的情况下。

  • 回溯法的时间复杂度通常是指数级的,对于较大的输入规模,计算量会急剧增加,导致效率低下。

✅ 修复方式:
  • 仅用于理解逻辑,不适用于大规模输入:在学习和理解排列生成的逻辑时,可以使用回溯法等方法。但在实际应用中,特别是面对大规模输入时,应选择更高效的算法或数据结构。

  • 可以考虑使用迭代法或其他优化算法来提高效率。


4. 全排列写回错误(补上前导0,数组排序就有问题了)

✅ 问题原因:
  • 在将全排列结果写回数组时,可能出现错误,导致排列顺序或内容不正确。

  • 这可能是由于字符串和数组之间的转换不正确,或者在处理过程中出现了逻辑错误。

✅ 修复方式:
  • 使用字符串逐位写回数组:在将字符串形式的排列写回数组时,逐位进行转换和赋值,确保每个字符都能正确地对应到数组中的相应位置。

  • 例如,可以通过遍历字符串,将每个字符转换为整数,并依次写入数组中。

3.原地算法

public class Solution {public static void nextPermutation(int[] nums) {if (nums == null || nums.length <= 1) {return;}// Step 1: Find the first decreasing element from the end.int i = nums.length - 2;while (i >= 0 && nums[i] >= nums[i + 1]) {i--;}// If such an element is found, find the element to swap with.if (i >= 0) {int j = nums.length - 1;while (nums[j] <= nums[i]) {j--;}// Step 2: Swap the elements.swap(nums, i, j);}// Step 3: Reverse the sequence after the position i.reverse(nums, i + 1);}private static void swap(int[] nums, int i, int j) {int temp = nums[i];nums[i] = nums[j];nums[j] = temp;}private static void reverse(int[] nums, int start) {int end = nums.length - 1;while (start < end) {swap(nums, start, end);start++;end--;}}}

示例

假设我们有一个数组 nums = {1, 3, 5, 4, 2}。我们的目标是找到这个排列的下一个字典序更大的排列。

步骤详解
  1. 寻找第一个降序对

    • 我们从后向前遍历数组,寻找第一个不符合升序的元素。

    • 遍历顺序:2 -> 4 -> 5(直到遇到 3)。

    • 在位置 i=1 处发现 3 < 5,这是我们要找的第一个降序点。

  2. 寻找大于 nums[i] 的最小元素

    • 从数组末尾开始向前查找,寻找第一个比 nums[1]=3 大的元素。

    • 查找顺序:2 -> 4(不满足条件),然后是 4,它比 3 大,且是最接近的一个。

    • 找到索引 j=3 处的元素 4

  3. 交换 nums[i]nums[j]

    • 交换 nums[1]nums[3],得到新的数组 {1, 4, 5, 3, 2}

  4. 反转 i+1 到数组末尾的部分

    • 反转 nums[2]nums[4],即 {5, 3, 2}

    • 反转后的结果为 {2, 3, 5}

    • 最终数组变为 {1, 4, 2, 3, 5}

结果

原始数组 {1, 3, 5, 4, 2} 经过上述步骤后变成了 {1, 4, 2, 3, 5},这正是它的下一个字典序排列。

关键点总结

  • 寻找降序对:从后向前找到第一个降序的位置,确保能找到一个比当前位置大的元素进行交换。

  • 寻找交换元素:在降序部分中找到刚好大于当前元素的值进行交换,保证新排列是下一个更大的排列。

  • 反转操作:将降序部分反转成升序,使得这部分成为最小的排列,从而保证整个数组是下一个字典序排列。

http://www.dtcms.com/a/292679.html

相关文章:

  • C语言:第11天笔记
  • ansible 批量 scp 和 load 镜像
  • Spring之【Bean工厂后置处理器】
  • PHP 8.0 超维意识编程终极指南(终篇)终极展望:PHP与宇宙意识融合跨维度架构模式超弦控制器增强版(1)
  • 最新植物大战僵尸杂交版最新版本2.5.1版,内置触屏+加速+全屏,附PC+安卓+iOS最全安装教程!
  • 阶段1--Linux中的文件服务器(FTP、NAS、SSH)
  • 前端_Javascript复习
  • 【C++】第十八节—一文万字详解 | map和set的使用
  • 网络安全第三次作业
  • Java学习第六十六部分——分布式系统架构
  • days32 :零基础学嵌入式之网络2.0
  • Coze智能体工作流:3分钟批量生成连贯人物一致的治愈图文
  • 远程调用图形浏览器(X11 转发)在 CentOS 7 上的安装操作
  • CentOS 7 安装nginx
  • 【LINUX】Centos 9使用nmcli更改IP
  • SpringBoot6-10(黑马)
  • linux-计划任务
  • 如何排查服务器 CPU 飙高
  • 本地大模型VRAM需求计算器:原理与实现详解
  • Spring Boot音乐服务器项目-上传音乐模块
  • [vue3] 自定义组件的v-model
  • Android ViewModel 深度解析:原理、使用与最佳实践
  • Android 中 实现日期选择功能(DatePickerDialog/MaterialDatePicker)
  • “鱼书”深度学习入门 笔记(2)第五章
  • MoonBit Meetup 杭州站丨 探讨AI基础软件的精彩回顾
  • API是什么,如何保障API安全?
  • 解决flex布局的元素高度超出父元素高度
  • AI网关是什么?为何而生?企业为什么需要AI网关?
  • 使用Kiro开发项目
  • SQL基础入门③ | 排序篇