陣列的合併和公升序排列 31 下乙個排列

2021-10-11 16:07:32 字數 1670 閱讀 1992

題目

實現獲取下乙個排列的函式,演算法需要將給定數字序列重新排列成字典序中下乙個更大的排列。

如果不存在下乙個更大的排列,則將數字重新排列成最小的排列(即公升序排列)。

必須原地修改,只允許使用額外常數空間。

以下是一些例子,輸入位於左側列,其相應輸出位於右側列。

1,2,3 → 1,3,2

3,2,1 → 1,2,3

1,1,5 → 1,5,1

cpp

class
概要我們需要找到給定數字列表的下乙個字典排列,而不是由給定陣列形成的數字。

解決方案

方法一:暴力法

演算法

在這種方法中,我們找出由給定陣列的元素形成的列表的每個可能的排列,並找出比給定的排列更大的排列。

但是這個方法是一種非常天真的方法,因為它要求我們找出所有可能的排列

這需要很長時間,實施起來也很複雜。

因此,這種方法根本無法通過。 所以,我們直接採用正確的方法。

複雜度分析

時間複雜度:o(n!),可能的排列總計有 n! 個。

空間複雜度:o(n),因為陣列將用於儲存排列。

方法二:一遍掃瞄

演算法

首先,我們觀察到對於任何給定序列的降序,沒有可能的下乙個更大的排列。

[9, 5, 4, 3, 1]

我們需要從右邊找到第一對兩個連續的數字 a[i] 和 a[i−1],它們滿足 a[i]>a[i−1]。現在,沒有對 a[i-1] 右側的重新排列可以建立更大的排列,因為該子陣列由數字按降序組成。因此,我們需要重新排列 a[i-1] 右邊的數字,包括它自己。

現在,什麼樣子的重新排列將產生下乙個更大的數字呢?我們想要建立比當前更大的排列。因此,我們需要將數字 a[i-1] 替換為位於其右側區域的數字中比它更大的數字,例如 a[j]。

我們交換數字 a[i−1] 和 a[j]。我們現在在索引 i−1 處有正確的數字。 但目前的排列仍然不是我們正在尋找的排列。我們需要通過僅使用 a[i-1]右邊的數字來形成最小的排列。 因此,我們需要放置那些按公升序排列的數字,以獲得最小的排列。

但是,請記住,在從右側掃瞄數字時,我們只是繼續遞減索引直到我們找到 a[i] 和 a[i−1] 這對數。其中,a[i]>a[i−1]。因此,a[i-1] 右邊的所有數字都已按降序排序。此外,交換 a[i−1] 和 a[j] 並未改變該順序。因此,我們只需要反轉 a[i-1] 之後的數字,以獲得下乙個最小的字典排列。

下面的動畫將有助於你理解:

public
複雜度分析時間複雜度:o(n),在最壞的情況下,只需要對整個陣列進行兩次掃瞄。

空間複雜度:o(1),沒有使用額外的空間,原地替換足以做到。

31 下乙個排列

public void nextpermutation int nums 從後向前找到第乙個不滿足逆序的元素 int i nums.length 2 for i 0 nums i nums i 1 i 注意,這裡有 可以排除含有重複元素的情況 從i 1位置開始,向後查詢比nums i 大的最小元素 ...

31 下乙個排列

實現獲取下乙個排列的函式,演算法需要將給定數字序列重新排列成字典序中下乙個更大的排列。如果不存在下乙個更大的排列,則將數字重新排列成最小的排列 即公升序排列 必須原地修改,只允許使用額外常數空間。以下是一些例子,輸入位於左側列,其相應輸出位於右側列。1,2,3 1,3,2 3,2,1 1,2,3 1...

31 下乙個排列

實現獲取下乙個排列的函式,演算法需要將給定數字序列重新排列成字典序中下乙個更大的排列。如果不存在下乙個更大的排列,則將數字重新排列成最小的排列 即公升序排列 必須原地修改,只允許使用額外常數空間。以下是一些例子,輸入位於左側列,其相應輸出位於右側列。1,2,3 1,3,2 3,2,1 1,2,3 1...