首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> C++ 入門

LeetCode 31 Next Permutation 完整解法:字典序下一排列算法詳解

     編輯:C++ 入門

題目描述

實現 **下一個排列**:將數字序列重排為**字典序中比當前排列大的最小排列**。若不存在 (已是最大排列),重排為**最小排列** (升序)。**必須原地修改**,O(1) 額外空間。

例:[1,2,3]→[1,3,2], [3,2,1]→[1,2,3], [1,1,5]→[1,5,1]。

核心算法:三步走

  1. 從右向左找「拐點」:找到**最右**的位置 i,使得 nums[i] < nums[i+1]。
    若不存在 (整個數組非遞增),說明已是最大排列,直接 **整體反轉** 為升序並返回。
  2. 從右向左找「換位者」:在 i 右側 (遞減區間) 找**最右**的位置 j,使得 nums[j] > nums[i]。
    (因右側遞減,最右滿足條件者即為「比 nums[i] 大的最小值」)。
  3. 交換 + 反轉尾部:交換 nums[i] 和 nums[j],然後將 i+1 到末尾 **反轉** (由遞減變遞增),得到最小增量。

完整 C++ 代碼

class Solution {
public:
    void nextPermutation(vector& nums) {
        int n = nums.size();
        int i = n - 2;
        // 1. 找拐點
        while (i >= 0 && nums[i] >= nums[i+1]) --i;
        if (i >= 0) {
            int j = n - 1;
            // 2. 找換位者
            while (j > i && nums[j] <= nums[i]) --j;
            swap(nums[i], nums[j]);
        }
        // 3. 反轉尾部 (i+1 到末尾)
        reverse(nums.begin() + i + 1, nums.end());
    }
};

Java 版本 (LeetCode 原題語言)

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

步驟圖解 (以 [1,3,2] 為例)

初始: [1, 3, 2]  (字典序: 132)
1. 找拐點: i=0 (nums[0]=1 < nums[1]=3)
2. 找換位者: j=2 (nums[2]=2 > 1, 且最右)
3. 交換: [2, 3, 1]
4. 反轉尾部 (i+1=1 到末尾): [2, 1, 3]  → 下一個排列 213 ✓

關鍵性質證明

  • 拐點右側必遞減:若不遞減,則存在更右的拐點,矛盾。
  • 換位者選最右滿足 >nums[i]:保證增量最小 (右側遞減,最右者值最小)。
  • 反轉尾部得最小排列**:交換後尾部仍遞減,反轉變遞增,即該前綴下的最小排列。

複雜度分析

  • 時間:O(n) — 三次單向掃描 + 一次反轉。
  • 空間:O(1) — 原地修改,僅常數額外變量。

避坑指南

  1. 拐點不存在時直接反轉整個數組**:i=-1 時 reverse(begin, end) 即升序。
  2. 換位者循環條件:nums[j] <= nums[i] (含等於),確保嚴格大於。
  3. 反轉範圍:i+1 到末尾,**包含 i+1**。
  4. 含重複元素**:算法天然支援 (如 [1,1,5]),因條件用 >= 和 <=。

C++ STL 一鍵調用

// 標準庫已實現
bool has_next = next_permutation(nums.begin(), nums.end());
// 返回 false 表示已是最大排列,且 nums 已重排為最小排列
// 完全符合題目要求,面試可先寫 STL 版,再手寫算法展示理解

結語

Next Permutation 是「字典序生成」的核心算法,亦是組合生成、回溯剪枝、排序算法的基石。掌握其 **「拐點-換位-反轉」** 三步曲,不僅能解決 LeetCode 31,更能舉一反三實現:全排列生成、上一個排列、字典序第 k 個排列、組合/子集字典序迭代等。面試中手寫無 Bug 版本是基本功標配。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved