[LeetCode解題攻略] 31. Next Permutation

更新於 發佈於 閱讀時間約 5 分鐘

題目描述

實現一個函數來重新排列數字序列,使其成為下一個更大的排列。如果不存在更大的排列,則將其排列為最小的順序(即升序)。

這個排列必須是 "原地" 完成,也就是說,只能使用常數級額外空間。


範例 1:

Input: nums = [1,2,3]
Output: [1,3,2]

範例 2:

Input: nums = [3,2,1]
Output: [1,2,3]

範例 3:

Input: nums = [1,1,5]
Output: [1,5,1]


解法一:雙指針法

思路

  1. 從右到左找到第一個數字 nums[i],使得 nums[i] < nums[i + 1]
  2. 再次從右到左找到第一個數字 nums[j],使得 nums[j] > nums[i]
  3. 交換 nums[i]nums[j]
  4. 反轉 nums[i+1:]

此算法的核心是找到一個較小數字的 "替代點",並通過反轉來確保後續部分是最小的排列。

程式碼實現

class Solution:
def nextPermutation(self, nums: List[int]) -> None:
"""
Do not return anything, modify nums in-place instead.
"""
n = len(nums)
i = n - 2

# Step 1: 找到第一個 nums[i] < nums[i + 1]
while i >= 0 and nums[i] >= nums[i + 1]:
i -= 1

if i >= 0:
# Step 2: 找到第一個 nums[j] > nums[i]
j = n - 1
while nums[j] <= nums[i]:
j -= 1
# Step 3: 交換 nums[i] 和 nums[j]
nums[i], nums[j] = nums[j], nums[i]

# Step 4: 反轉 nums[i + 1:]
nums[i + 1:] = reversed(nums[i + 1:])

時間與空間複雜度

  • 時間複雜度: O(n),最多遍歷兩次數組。
  • 空間複雜度: O(1),為原地操作。


解法二:暴力法

思路

  1. 將當前排列的所有排列生成出來。
  2. 找到當前排列後的下一個排列。

該解法的時間複雜度極高,適合用於理解問題,但不適合實際應用。

程式碼實現

class Solution:
def nextPermutation(self, nums: List[int]) -> None:
"""
Do not return anything, modify nums in-place instead.
"""
# 生成輸入列表的所有排列
all_perms = sorted(set(permutations(nums)))
# 找到當前排列的索引
current_index = all_perms.index(tuple(nums))
# 如果存在下一個排列,則更新 nums
if current_index + 1 < len(all_perms):
nums[:] = list(all_perms[current_index + 1])
else:
# 如果是最後一個排列,則返回第一個排列(排序後的順序)
nums[:] = list(all_perms[0])

時間與空間複雜度

  • 時間複雜度: O(n!),生成所有排列的時間成本。
  • 空間複雜度: O(n!),存儲所有排列的空間成本。


總結

  1. 雙指針法 是解決此問題的最佳方法,其時間效率高,且使用常數額外空間。
  2. 暴力法 雖然直觀,但無法滿足大數據規模下的性能要求。

在實際應用中,應優先使用雙指針法,確保代碼簡潔且性能優越。

歡迎來到我的部落格!這裡記錄了軟體工程師的日常生活點滴,並分享程式設計與演算法的實用教學。無論你是初學者還是有經驗的開發者,都能在這裡找到深入淺出的技術解析與實戰技巧。此外,我也會分享工作中的心路歷程與學習心得,讓你不僅學到技術,更能瞭解軟體開發的實際應用與挑戰。希望透過這個平台,能與你共同成長,激發對技術的熱情!
留言0
查看全部
avatar-img
發表第一個留言支持創作者!
給定一個字符串 s 和一個由多個單詞組成的列表 words,請找出所有能夠在字符串 s 中連續拼接所有單詞的子字符串的起始索引。
實作一個函數 divide(dividend, divisor),計算兩個整數 dividend 和 divisor 的商,並返回其結果。
實作一個函數 strStr(haystack, needle),用來找出字串 needle 在字串 haystack 中第一次出現的索引。如果 needle 不是 haystack 的一部分,則返回 -1。
給定一個整數數組 nums 和一個值 val,需要就地刪除數組中所有等於 val 的元素,並返回刪除後數組的新長度。 要求在 O(1) 額外空間內完成操作,並且元素的相對順序不需要保持一致。
給定一個按非降序排序的整數數組 nums,就地刪除重複項,使得每個元素只出現一次。元素的相對順序應保持相同。然後傳回 nums 中唯一元素的數量。
給定一個鏈表,將鏈表的節點每 k 個一組進行反轉,並返回修改後的鏈表。如果節點總數不是 k 的倍數,則保留最後剩餘節點的順序。要求在不改變節點值的情況下進行反轉(即直接操作鏈表結構)。
給定一個字符串 s 和一個由多個單詞組成的列表 words,請找出所有能夠在字符串 s 中連續拼接所有單詞的子字符串的起始索引。
實作一個函數 divide(dividend, divisor),計算兩個整數 dividend 和 divisor 的商,並返回其結果。
實作一個函數 strStr(haystack, needle),用來找出字串 needle 在字串 haystack 中第一次出現的索引。如果 needle 不是 haystack 的一部分,則返回 -1。
給定一個整數數組 nums 和一個值 val,需要就地刪除數組中所有等於 val 的元素,並返回刪除後數組的新長度。 要求在 O(1) 額外空間內完成操作,並且元素的相對順序不需要保持一致。
給定一個按非降序排序的整數數組 nums,就地刪除重複項,使得每個元素只出現一次。元素的相對順序應保持相同。然後傳回 nums 中唯一元素的數量。
給定一個鏈表,將鏈表的節點每 k 個一組進行反轉,並返回修改後的鏈表。如果節點總數不是 k 的倍數,則保留最後剩餘節點的順序。要求在不改變節點值的情況下進行反轉(即直接操作鏈表結構)。
你可能也想看
Google News 追蹤
Thumbnail
現代社會跟以前不同了,人人都有一支手機,只要打開就可以獲得各種資訊。過去想要辦卡或是開戶就要跑一趟銀行,然而如今科技快速發展之下,金融App無聲無息地進到你生活中。但同樣的,每一家銀行都有自己的App時,我們又該如何選擇呢?(本文係由國泰世華銀行邀約) 今天我會用不同角度帶大家看這款國泰世華CUB
Thumbnail
嘿,大家新年快樂~ 新年大家都在做什麼呢? 跨年夜的我趕工製作某個外包設計案,在工作告一段落時趕上倒數。 然後和兩個小孩過了一個忙亂的元旦。在深夜時刻,看到朋友傳來的解籤網站,興致勃勃熬夜體驗了一下,覺得非常好玩,或許有人玩過了,但還是想寫上來分享紀錄一下~
Thumbnail
題目敘述 Sort Array by Increasing Frequency Leetcode #1636 給定一個輸入陣列,請依照出現頻率的多寡從低頻到高頻排列陣列元素。 如果有兩個元素的出現頻率相同,依照元素大小從大到小排列。 測試範例 Example 1: Input: nums
Thumbnail
本文章討論如何使用動態規劃和回頭查看技巧來計算最長遞增子序列的長度,並提供了相關的測試案例和範例。本文還包括了詳細的演算法和程式碼示例,以及時間和空間複雜度的分析。
Thumbnail
Leetcode 精選75題 題目與題解 熱門考點 目錄 (持續更新中) 建議從左側目錄 或者 按Ctrl+F輸入關鍵字進行搜尋
Thumbnail
給定一個輸入非負整樹陣列nums,請找出k值,使得陣列中恰好有k個元素大於等於 k。如果無解,回傳-1。尋找k值的方法包括排序法和二分搜尋法,時間複雜度都為O(n log n),空間複雜度為O(1)。關鍵知識點是當解空間具有遞增或遞減的性質時,可以用二分搜尋法加快搜尋效率。
Thumbnail
題目已經給了依照起點升序排列好的區間陣列。 接下來新插入一個區間,插入後如果和原本的區間重疊,請把他們合併,要求我們輸出插入後的結果。 這是一個線性掃苗,所需時間為O(n)的演算法。 題目已經幫我們排序好區間順序,我們只要接著依序檢查區間、(假如有重疊的話)合併區間。
Thumbnail
題目會給定一個陣列nums和一個目標值goal。計算子陣列總和=goal的數目有多少。演算法包含前綴和和字典的技巧,時間複雜度為O(n),空間複雜度為O(n)。
Thumbnail
題目敘述 題目會給定我們兩個字串。 第一個是指定順序的字串order。 第二個是輸入字串s。 要求我們依據order給定的順序,重新排列s。 如果出現order中沒有出現的字母,任意位置皆可。 合法答案可能不只一組,輸出其中一種即可。 題目的原文敘述 測試範例 Example
Thumbnail
題目敘述 題目會給定一個輸入字串s和一套編碼規則,要求我們針對字串s進行解碼,並且以字串的形式返回答案。 編碼規則: 數字[字串] -> []內的字串以對應倍數做展開,而且允許巢狀編碼。 例如: 3[a] 解碼完就是 aaa 2[bc] 解碼完就是 bcbc 2[a2[b]] = 2
Thumbnail
題目敘述 題目會給定我們一個整數陣列nums,要求我們把裡面的0做元素交換,把0都搬到陣列的右邊。題目要求必須in-place在原本的陣列裡面做操作,不可以額外建立新的陣列。 題目的原文敘述 測試範例 Example 1: Input: nums = [0,1,0,3,12] Outpu
Thumbnail
題目敘述 題目會給兩個陣列nums1和nums2。 題目要求我們從中同步選擇長度為k的子序列,並且最大化子序列的分數, 回傳最高的分數值。 分數的定義: 分數 = (nums1[i0] + nums1[i1] +...+ nums1[ik - 1]) * min(nums2[i0] ,
Thumbnail
現代社會跟以前不同了,人人都有一支手機,只要打開就可以獲得各種資訊。過去想要辦卡或是開戶就要跑一趟銀行,然而如今科技快速發展之下,金融App無聲無息地進到你生活中。但同樣的,每一家銀行都有自己的App時,我們又該如何選擇呢?(本文係由國泰世華銀行邀約) 今天我會用不同角度帶大家看這款國泰世華CUB
Thumbnail
嘿,大家新年快樂~ 新年大家都在做什麼呢? 跨年夜的我趕工製作某個外包設計案,在工作告一段落時趕上倒數。 然後和兩個小孩過了一個忙亂的元旦。在深夜時刻,看到朋友傳來的解籤網站,興致勃勃熬夜體驗了一下,覺得非常好玩,或許有人玩過了,但還是想寫上來分享紀錄一下~
Thumbnail
題目敘述 Sort Array by Increasing Frequency Leetcode #1636 給定一個輸入陣列,請依照出現頻率的多寡從低頻到高頻排列陣列元素。 如果有兩個元素的出現頻率相同,依照元素大小從大到小排列。 測試範例 Example 1: Input: nums
Thumbnail
本文章討論如何使用動態規劃和回頭查看技巧來計算最長遞增子序列的長度,並提供了相關的測試案例和範例。本文還包括了詳細的演算法和程式碼示例,以及時間和空間複雜度的分析。
Thumbnail
Leetcode 精選75題 題目與題解 熱門考點 目錄 (持續更新中) 建議從左側目錄 或者 按Ctrl+F輸入關鍵字進行搜尋
Thumbnail
給定一個輸入非負整樹陣列nums,請找出k值,使得陣列中恰好有k個元素大於等於 k。如果無解,回傳-1。尋找k值的方法包括排序法和二分搜尋法,時間複雜度都為O(n log n),空間複雜度為O(1)。關鍵知識點是當解空間具有遞增或遞減的性質時,可以用二分搜尋法加快搜尋效率。
Thumbnail
題目已經給了依照起點升序排列好的區間陣列。 接下來新插入一個區間,插入後如果和原本的區間重疊,請把他們合併,要求我們輸出插入後的結果。 這是一個線性掃苗,所需時間為O(n)的演算法。 題目已經幫我們排序好區間順序,我們只要接著依序檢查區間、(假如有重疊的話)合併區間。
Thumbnail
題目會給定一個陣列nums和一個目標值goal。計算子陣列總和=goal的數目有多少。演算法包含前綴和和字典的技巧,時間複雜度為O(n),空間複雜度為O(n)。
Thumbnail
題目敘述 題目會給定我們兩個字串。 第一個是指定順序的字串order。 第二個是輸入字串s。 要求我們依據order給定的順序,重新排列s。 如果出現order中沒有出現的字母,任意位置皆可。 合法答案可能不只一組,輸出其中一種即可。 題目的原文敘述 測試範例 Example
Thumbnail
題目敘述 題目會給定一個輸入字串s和一套編碼規則,要求我們針對字串s進行解碼,並且以字串的形式返回答案。 編碼規則: 數字[字串] -> []內的字串以對應倍數做展開,而且允許巢狀編碼。 例如: 3[a] 解碼完就是 aaa 2[bc] 解碼完就是 bcbc 2[a2[b]] = 2
Thumbnail
題目敘述 題目會給定我們一個整數陣列nums,要求我們把裡面的0做元素交換,把0都搬到陣列的右邊。題目要求必須in-place在原本的陣列裡面做操作,不可以額外建立新的陣列。 題目的原文敘述 測試範例 Example 1: Input: nums = [0,1,0,3,12] Outpu
Thumbnail
題目敘述 題目會給兩個陣列nums1和nums2。 題目要求我們從中同步選擇長度為k的子序列,並且最大化子序列的分數, 回傳最高的分數值。 分數的定義: 分數 = (nums1[i0] + nums1[i1] +...+ nums1[ik - 1]) * min(nums2[i0] ,