力扣#31 下一个排列(难度:中等)

本文详细介绍了如何实现获取整数数组下一个字典序排列的算法,包括找到第一个下降位置、交换数字以及翻转部分序列的过程。示例展示了如何将[4,2,0,2,3,2,0]转换为[4,2,0,3,0,2,2]。代码示例中展示了具体实现方法。

题目:

实现获取 下一个排列 的函数,算法需要将给定数字序列重新排列成字典序中下一个更大的排列。

如果不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排列)。

必须 原地 修改,只允许使用额外常数空间。

示例 :

输入:[4,2,0,2,3,2,0]

输出:[4,2,0,3,0,2,2]

解题思路:

找下一个排列更大的数,我们尽可能的将低位的数字变大,其实就是将k位到最低位的所有数作为候选,判断是否有更大的数可以填入k位中,换句话说,我们要找的第k位其实就是从低位到高位第一个下降的数。

进行一下步骤:

1. 从后往前找,找到第一个下降的位置,记为 k。注意k 以后的位置是降序的。

2. 从 k 往后找,找到最小的比 k 要大的数。

3. 将两者交换。注意此时 k 以后的位置仍然是降序的。

4. 直接将 k 以后的部分翻转(变为升序)。

注意:如果在步骤 1 中找到头部还没找到,说明该序列已经是字典序最大的排列。按照题意,我们要将数组重新排列成最小的排列。

代码示例:

    public void nextPermutation(int[] nums) {
        int i = nums.length - 2;
        while (i >= 0 && nums[i] >= nums[i + 1]) {
            i--;
        }
        if (i >= 0) {
            int j = nums.length - 1;
            while (j >= 0 && nums[i] >= nums[j]) {
                j--;
            }
            swap(nums, i, j);
        }
        reverse(nums, i + 1);
    }

    public void swap(int[] nums, int i, int j) {
        int temp = nums[i];
        nums[i] = nums[j];
        nums[j] = temp;
    }

    public void reverse(int[] nums, int start) {
        int left = start, right = nums.length - 1;
        while (left < right) {
            swap(nums, left, right);
            left++;
            right--;
        }
    }

### LeetCode 中等难度#### 目概述 LeetCode 上的中等难度目涵盖了多种算法数据结构的知识点。这些目不仅考察基本编程能力,还涉及更深层次的逻辑思维和优化技巧[^1]。 #### 解决方案分析 以下是几个典型的中等难度目及其解决方案: --- ##### **单链表操作** 针对单链表的操作问,通常需要考虑节点间的比较以及插入方式的选择(头插、尾插或中间插入)。这类问的时间复杂度可以通过特定方法优化至 \(O(n \log n)\)。 一种常见的解决策略是利用归并排序的思想来处理链表中的元素排列。具体实现如下: ```java class ListNode { int val; ListNode next; ListNode(int x) { this.val = x; } } public ListNode sortList(ListNode head) { if (head == null || head.next == null) return head; // 使用快慢指针找到链表中点 ListNode slow = head, fast = head, prev = null; while (fast != null && fast.next != null) { prev = slow; slow = slow.next; fast = fast.next.next; } prev.next = null; // 断开链表 // 归并排序递归调用 ListNode l1 = sortList(head); ListNode l2 = sortList(slow); // 合并两个有序链表 return merge(l1, l2); } private ListNode merge(ListNode l1, ListNode l2) { ListNode dummy = new ListNode(0), curr = dummy; while (l1 != null && l2 != null) { if (l1.val < l2.val) { curr.next = l1; l1 = l1.next; } else { curr.next = l2; l2 = l2.next; } curr = curr.next; } curr.next = (l1 != null ? l1 : l2); return dummy.next; } ``` --- ##### **打家劫舍问** 此问是动态规划的经典应用之一。目标是在不触发报警的情况下最化抢劫金额。状态转移方程定义为 `dp[i]` 表示前 `i` 户人家能抢到的最金额,则有以下关系成立: \[ dp[i] = \max(dp[i-2] + nums[i], dp[i-1]) \][^2] 代码实现如下: ```java public int rob(int[] nums) { int length = nums.length; if (length == 1) return nums[0]; int[] dp = new int[length]; dp[0] = nums[0]; dp[1] = Math.max(nums[0], nums[1]); for (int i = 2; i < length; i++) { dp[i] = Math.max(dp[i - 2] + nums[i], dp[i - 1]); } return dp[length - 1]; } ``` --- ##### **数加法** 当涉及到非常的整数运算时,传统的数值类型可能无法满足需求。此时可采用字符串模拟的方式完成计算[^3]。例如两链表表示的数相加问,其核心在于逐位累加并记录进位值。 代码示例: ```python def addTwoNumbers(l1, l2): carry = 0 result_head = current_node = ListNode(0) while l1 or l2 or carry: v1 = l1.val if l1 else 0 v2 = l2.val if l2 else 0 sum_val = v1 + v2 + carry carry = sum_val // 10 digit = sum_val % 10 current_node.next = ListNode(digit) current_node = current_node.next if l1: l1 = l1.next if l2: l2 = l2.next return result_head.next ``` --- ##### **单词搜索** 给定二维网格与一个单词,判断该单词是否能够由连续相邻字符组成。这一问可通过深度优先搜索(DFS)配合回溯技术求解[^4]。 代码片段展示: ```java public boolean exist(char[][] board, String word) { int rows = board.length; int cols = board[0].length; boolean[][] visited = new boolean[rows][cols]; for (int r = 0; r < rows; ++r) { for (int c = 0; c < cols; ++c) { if (dfs(board, word, 0, r, c, visited)) { return true; } } } return false; } private boolean dfs(char[][] b, String w, int idx, int row, int col, boolean[][] vis) { if (idx >= w.length()) return true; if (row < 0 || col < 0 || row >= b.length || col >= b[row].length) return false; if (vis[row][col] || b[row][col] != w.charAt(idx)) return false; vis[row][col] = true; boolean found = dfs(b, w, idx + 1, row + 1, col, vis) || dfs(b, w, idx + 1, row - 1, col, vis) || dfs(b, w, idx + 1, row, col + 1, vis) || dfs(b, w, idx + 1, row, col - 1, vis); vis[row][col] = false; return found; } ``` --- #### 总结 上述几类问覆盖了链表操作、动态规划、字符串处理及图遍历等多个领域。每种类型的解答均需注重边界条件处理与性能优化。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值