每日一題-輪轉(zhuǎn)數(shù)組

1. 題目描述

題目鏈接: 輪轉(zhuǎn)數(shù)組

給定一個(gè)整數(shù)數(shù)組 nums,將數(shù)組中的元素向右輪轉(zhuǎn) k **個(gè)位置,其中 k **是非負(fù)數(shù)。
示例 1:

輸入: nums = [1,2,3,4,5,6,7], k = 3
輸出: [5,6,7,1,2,3,4]解釋:
向右輪轉(zhuǎn) 1 步: [7,1,2,3,4,5,6]
向右輪轉(zhuǎn) 2 步: [6,7,1,2,3,4,5]
向右輪轉(zhuǎn) 3 步: [5,6,7,1,2,3,4]

示例 2:

輸入: nums = [-1,-100,3,99], k = 2
輸出: [3,99,-1,-100]
解釋: 
向右輪轉(zhuǎn) 1 步: [99,-1,-100,3]
向右輪轉(zhuǎn) 2 步: [3,99,-1,-100]

2. 使用額外的數(shù)組

一種比較簡(jiǎn)單的方法,是創(chuàng)建一個(gè)新的數(shù)組,將原數(shù)組的元素按照旋轉(zhuǎn)后的位置依次放入新數(shù)組中。這種方法需要O(n)的額外空間,其中n是數(shù)組的長(zhǎng)度。

下面是一個(gè)詳細(xì)說(shuō)明和示意圖,演示如何使用額外的新數(shù)組來(lái)實(shí)現(xiàn)數(shù)組向右旋轉(zhuǎn)。假設(shè)我們有一個(gè)數(shù)組 nums = [1, 2, 3, 4, 5, 6, 7],要將其向右旋轉(zhuǎn)3個(gè)位置(k=3),我們將創(chuàng)建一個(gè)新數(shù)組 new_nums,并按照旋轉(zhuǎn)后的位置依次將元素從原數(shù)組中放入新數(shù)組中。

創(chuàng)建一個(gè)新數(shù)組 new_nums,與原數(shù)組 nums 同樣大小,初始都為0:

原數(shù)組:  [1, 2, 3, 4, 5, 6, 7]
新數(shù)組:  [0, 0, 0, 0, 0, 0, 0]

遍歷原數(shù)組 nums 中的每個(gè)元素,將元素按照旋轉(zhuǎn)后的位置放入新數(shù)組 new_nums 中。為了確定每個(gè)元素的新位置,我們可以使用以下公式:新位置 = (當(dāng)前位置 + k) % 數(shù)組長(zhǎng)度。 當(dāng)前例子中,k=3,數(shù)組長(zhǎng)度為7。

開(kāi)始遍歷,第一個(gè)元素1的新位置為 (0 + 3) % 7 = 3,所以將1放入新數(shù)組的第3個(gè)位置:

原數(shù)組:  [1, 2, 3, 4, 5, 6, 7]
新數(shù)組:  [0, 0, 0, 1, 0, 0, 0]

第二個(gè)元素2的新位置為 (1 + 3) % 7 = 4,所以將2放入新數(shù)組的第4個(gè)位置:

原數(shù)組:  [1, 2, 3, 4, 5, 6, 7]
新數(shù)組:  [0, 0, 0, 1, 2, 0, 0]

繼續(xù)這個(gè)過(guò)程,將所有元素按照新位置放入新數(shù)組:

原數(shù)組:  [1, 2, 3, 4, 5, 6, 7]
新數(shù)組:  [5, 6, 7, 1, 2, 3, 4]

最終旋轉(zhuǎn)完成,將新數(shù)組 new_nums 的數(shù)據(jù)拷貝到原數(shù)組當(dāng)中即可:

原數(shù)組:  [5, 6, 7, 1, 2, 3, 4]
新數(shù)組:  [5, 6, 7, 1, 2, 3, 4]

這個(gè)過(guò)程中,我們創(chuàng)建了一個(gè)新數(shù)組,并根據(jù)旋轉(zhuǎn)后的位置依次將原數(shù)組的元素放入新數(shù)組。這種方法需要O(n)的額外空間,其中n是數(shù)組的長(zhǎng)度

3. 數(shù)組翻轉(zhuǎn)

這道題是將數(shù)組中的元素從一處移動(dòng)到另一處,通??梢钥紤]反轉(zhuǎn)這一操作,因?yàn)榉崔D(zhuǎn)是可逆的。在向右旋轉(zhuǎn)問(wèn)題中,我們可以將旋轉(zhuǎn)操作看作是將數(shù)組分為兩部分,然后將這兩部分交換位置。反轉(zhuǎn)這兩個(gè)部分的順序就可以實(shí)現(xiàn)向右旋轉(zhuǎn)。

這里通過(guò)數(shù)組翻轉(zhuǎn)來(lái)實(shí)現(xiàn)向右旋轉(zhuǎn)時(shí),可以通過(guò)三次翻轉(zhuǎn)操作來(lái)完成。這個(gè)方法不需要額外的數(shù)組空間,只需要在原數(shù)組上進(jìn)行操作。下面詳細(xì)說(shuō)明其中的過(guò)程,假設(shè)有一個(gè)數(shù)組 nums = [1, 2, 3, 4, 5, 6, 7],要將其向右旋轉(zhuǎn)3個(gè)位置(k=3):

首先,將整個(gè)數(shù)組翻轉(zhuǎn)。這將把數(shù)組的最后k個(gè)元素移到數(shù)組的前面:

原數(shù)組:  [1, 2, 3, 4, 5, 6, 7]
翻轉(zhuǎn)后:  [7, 6, 5, 4, 3, 2, 1]

此時(shí),數(shù)組的前3個(gè)元素是原數(shù)組的最后3個(gè)元素,接下來(lái),翻轉(zhuǎn)前k個(gè)元素。這將把原數(shù)組的最后k個(gè)元素移動(dòng)到數(shù)組的末尾。

前k個(gè)元素: [7, 6, 5]
翻轉(zhuǎn)后:    [5, 6, 7]

此時(shí),數(shù)組的前3個(gè)元素是原數(shù)組的最后3個(gè)元素,而數(shù)組的剩余部分是原數(shù)組的前面部分。最后,翻轉(zhuǎn)剩下的元素(原數(shù)組的前n-k個(gè)元素),將它們移動(dòng)到正確的位置。

剩余的元素: [1, 2, 3, 4]
翻轉(zhuǎn)后:    [4, 3, 2, 1]

此時(shí),數(shù)組的前3個(gè)元素是原數(shù)組的最后3個(gè)元素,數(shù)組的剩余部分是原數(shù)組的前面部分。旋轉(zhuǎn)完成,數(shù)組中的元素已經(jīng)按照要求向右旋轉(zhuǎn)3個(gè)位置。

最終結(jié)果: [5, 6, 7, 1, 2, 3, 4]

通過(guò)三次翻轉(zhuǎn)操作,我們成功地將原數(shù)組向右旋轉(zhuǎn)了3個(gè)位置,而且沒(méi)有使用額外的數(shù)組空間。這個(gè)方法是一個(gè)高效且常用的旋轉(zhuǎn)數(shù)組的方式。

4. 環(huán)形替換

將數(shù)組看作一個(gè)環(huán),從第一個(gè)元素開(kāi)始,計(jì)算每個(gè)元素在旋轉(zhuǎn)后的位置,然后將元素替換到該位置,直到處理完所有元素,這個(gè)過(guò)程可能需要經(jīng)過(guò)多輪循環(huán)。下面我們來(lái)展示下每輪循環(huán)的具體流程。

假設(shè)我們有一個(gè)數(shù)組 nums,以及需要將它向右旋轉(zhuǎn)k個(gè)位置,其中k等于3。數(shù)組 nums 如下:

nums = [1, 2, 3, 4, 5, 6]

我們將按照下面的步驟開(kāi)始移動(dòng)元素:

  1. 選擇一個(gè)起始位置,通常從數(shù)組的第一個(gè)元素開(kāi)始,即 nums[0]。
  2. 獲取到其最終所在位置,根據(jù)旋轉(zhuǎn)的規(guī)則來(lái)獲取。對(duì)于向右旋轉(zhuǎn),下一個(gè)位置是當(dāng)前位置加上k,即 0 + 3 = 3
  3. 保留該位置的數(shù)據(jù)(nums[3],即4),然后將 nums[0] 的數(shù)放到下標(biāo)等于3 的位置下。
  4. 繼續(xù)移動(dòng)到下一個(gè)位置,根據(jù)旋轉(zhuǎn)規(guī)則,下一個(gè)位置是 3 + 3 = 6,此時(shí)6 大于數(shù)組長(zhǎng)度,需要取余數(shù)組長(zhǎng)度,此時(shí)獲取到0, 將之前保留的nums[3] 的數(shù)據(jù)賦值到nums[0] 當(dāng)中。
  5. 發(fā)現(xiàn)回到原點(diǎn)位置,此時(shí)完成一輪循環(huán)。

這個(gè)過(guò)程的圖示如下:

初始狀態(tài): [1, 2, 3, 4, 5, 6]
第一步:    1   2   3   4   5   6
           ↓
第二步:    1   2   3   1   5   6
               ↓
第三步:    4   2   3   1   5   6

通過(guò)一輪循環(huán),能夠?qū)⒉糠謹(jǐn)?shù)據(jù)成功放置到正確的位置下。這里我們需要證明下,從原點(diǎn)出發(fā)后,經(jīng)過(guò)一輪循環(huán),再次回到原點(diǎn)的過(guò)程中,中間會(huì)不會(huì)經(jīng)過(guò)相同的下標(biāo)。因?yàn)槊拷?jīng)過(guò)一個(gè)下標(biāo),都會(huì)將該元素放到正確的位置,如果重復(fù)到達(dá),此時(shí)是有問(wèn)題的。

這里我們可以使用數(shù)據(jù)歸納法,來(lái)證明遍歷的過(guò)程是不會(huì)重復(fù)到達(dá)某個(gè)數(shù)組下標(biāo)位置的,除非回到了開(kāi)始的地方。假設(shè)我們?cè)诃h(huán)形數(shù)組中每次向前走k步,但不回到原點(diǎn)。現(xiàn)在我們使用數(shù)學(xué)歸納法來(lái)證明,如果我們?cè)谀骋徊街貜?fù)達(dá)到了某個(gè)位置p,并且之前沒(méi)有回到原點(diǎn),那么前一個(gè)位置p-1也一定重復(fù)到達(dá)了,以此類(lèi)推,最終說(shuō)明第一個(gè)重復(fù)到達(dá)的點(diǎn)肯定是原點(diǎn)。

但是一次循環(huán),并不一定能夠經(jīng)過(guò)所有的元素。下面我們需要去獲取到每次循環(huán)能夠到達(dá)的元素的數(shù)量,從而獲取到需要循環(huán)遍歷的次數(shù)。

每次從起點(diǎn)出發(fā),繞行一圈,再次回到原點(diǎn)的過(guò)程中,其經(jīng)過(guò)的元素的個(gè)數(shù)可以通過(guò)下面公式來(lái)獲取到,公式如下:

(kx + i) % n = i 

為什么是這條公式呢? 因?yàn)榛氐皆c(diǎn),說(shuō)明是經(jīng)過(guò)的長(zhǎng)度必須是數(shù)組長(zhǎng)度 n 的整數(shù)倍,經(jīng)過(guò)的長(zhǎng)度用kx來(lái)表示, k 代表每次移動(dòng)的步數(shù),而x代表移動(dòng)的次數(shù)。

kxn 的整數(shù)倍的數(shù)有無(wú)數(shù)個(gè),我們只需要第一次到達(dá)原點(diǎn)時(shí)所需要移動(dòng)的步數(shù),需要獲取到kx 的最小值。因此kx 應(yīng)該是xk 的最小公倍數(shù),這里最小公倍數(shù)用LCM來(lái)表示。

因此,每次移動(dòng)元素的個(gè)數(shù)為 x = (LCM(k,n)/k),其中參數(shù)k 和參數(shù)n 都是已知的,基于此能夠獲取到每次移動(dòng)元素的個(gè)數(shù)。下面舉個(gè)例子來(lái)說(shuō)明一下,數(shù)組如下:

nums = [1, 2, 3, 4, 5, 6]

數(shù)組需要向右輪轉(zhuǎn)2個(gè)位置,此時(shí)k = 3, n = 6, 基于此獲取到最小公倍數(shù) = 6?;诠?code>x = (LCM(k,n)/k),可以獲取到每次循環(huán)移動(dòng)元素的個(gè)數(shù),這個(gè)例子中,每次循環(huán)移動(dòng)元素的格式為2。

循環(huán)的次數(shù),為n / x, n 代表數(shù)組的長(zhǎng)度,x 代表每次循環(huán)移動(dòng)元素的數(shù)量。然后每次循環(huán)的開(kāi)頭,都是從上一次循環(huán)的起點(diǎn)的后一個(gè)元素出發(fā)的。 通過(guò)這n / x 次的循環(huán),就可以將所有數(shù)據(jù)移動(dòng)到正確的位置。

因此,在這道題中,如果我們使用環(huán)形替換,此時(shí)需要先計(jì)算出最小公倍數(shù)LCM(k,n), 然后再基于公式LCM(k,n)/k 獲取到每次移動(dòng)元素的個(gè)數(shù),然后再通過(guò)n / 每次移動(dòng)元素個(gè)數(shù) 獲取到需要循環(huán)的次數(shù),公式可以按照下面流程來(lái)進(jìn)行轉(zhuǎn)換:

循環(huán)次數(shù) = n / (lcm(k,n) / k) = nk / lcm(k,n) =  gcd(n,k)

其中gcd(n,k) 代表 nk 的最小公約數(shù)。每次循環(huán)中,就從某個(gè)起點(diǎn)出發(fā),將數(shù)據(jù)移動(dòng)到目標(biāo)位置。

下面我們通過(guò)一個(gè)完整的例子,展示整個(gè)流程,首先數(shù)組如下:

nums = [1, 2, 3, 4, 5, 6]

通過(guò)上面gcd(n,k) 公式計(jì)算,獲取到最大公約數(shù)為3,此時(shí)需要進(jìn)行三輪循環(huán)。

開(kāi)始第一輪移動(dòng),起點(diǎn)坐標(biāo)為0, 目標(biāo)下標(biāo)為3 , 此時(shí)將nums[0] 的數(shù)據(jù)放到nums[3] 下面;第二步則將原本nums[3] 的元素進(jìn)行移動(dòng),將其放到 (3+3) % 6 = 0的位置下,接下來(lái)發(fā)現(xiàn)已經(jīng)回到原點(diǎn),結(jié)束第一輪循環(huán),如下:

初始狀態(tài): [1, 2, 3, 4, 5, 6]
第一步:    1   2   3   4   5   6
                     ↓
第二步:    1   2   3   1   5   6
          ↓     
第三步:    4   2   3   1   5   6

開(kāi)始第二輪移動(dòng),本次起點(diǎn)坐標(biāo)為1 , 目標(biāo)下標(biāo)為 4 , 此時(shí)將nums[1] 的數(shù)據(jù)放到nums[4] 下面;第二部將原本nums[4] 的元素進(jìn)行移動(dòng),將其放到(4+3) % 6 == 1 的位置下。此時(shí)又回到了原點(diǎn),結(jié)束了第二輪循環(huán),具體流程如下:

初始狀態(tài): [4, 2, 3, 1, 5, 6]
第一步:    4   2   3   1   5   6
                          ↓
第二步:    1   2   3   1   2   6
              ↓
第三步:    4   5   3   1   2   6

開(kāi)始第三輪移動(dòng),本次起點(diǎn)坐標(biāo)為2 , 目標(biāo)下標(biāo)為 5 , 此時(shí)將nums[2] 的數(shù)據(jù)放到nums[5] 下面;第二部將原本nums[5] 的元素進(jìn)行移動(dòng),將其放到(5+3) % 6 == 2 的位置下。此時(shí)又回到了原點(diǎn),結(jié)束了第三輪循環(huán),具體流程如下:

初始狀態(tài): [4, 5, 3, 1, 2, 6]
第一步:    4   5   3   1   2   6
                              ↓
第二步:    1   2   3   1   2   3
                  ↓
第三步:    4   5   6   1   2   3

此時(shí)經(jīng)過(guò)幾輪循環(huán),成功將數(shù)據(jù)放置到正確的位置,此時(shí)時(shí)間復(fù)雜度為O(n),空間復(fù)雜度為O(1)。

5. 總結(jié)

上面描述了輪轉(zhuǎn)數(shù)組這道題的三種解法,包括使用額外數(shù)組,反轉(zhuǎn)數(shù)組,環(huán)形替換這三種方法,同時(shí)也展示了各個(gè)解法過(guò)程中數(shù)據(jù)的流轉(zhuǎn)的順序,希望對(duì)于理解該題能夠起到積極的作用。
代碼已經(jīng)上傳到 github 上,有興趣可以看看。

本文由博客一文多發(fā)平臺(tái) OpenWrite 發(fā)布!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容