《力扣算法訓練提升》圖解數組篇-打卡數組統計-【189】旋轉數組


《力扣算法訓練提升》圖解數組篇-打卡數組統計-【189】旋轉數組

今日份打卡題[189. 旋轉數組]

打卡

給定一個數組,將數組中的元素向右移動 k 個位置,其中 k 是非負數。

具體描述

算法描述

解題討論

算法討論1

算法討論2

討論歸納一:輔助數組,划分旋轉區域

第一步:根據數組長度 N 和跨步 K 計算出需要轉移至數組頭部的元素個數
第二步:將數組划分為兩個區域
	注意:(邏輯區域,思想區域,這里是為了方便理解,不需要真實狀態標注)
	區域一:需要旋轉到右邊的數(頭部需要旋轉到尾部的元素)
	區域二:需要旋轉到左邊的數(尾部需要旋轉到頭部的元素)
第三步:遷移數據到輔助數組
	先遷移區域二,在遷移區域一
第四步:拷貝回原數組

區域划分圖

區域划分

動畫模擬

區域旋轉動畫

示例一:輔助數組,划分旋轉區域

public void rotate(int[] nums, int k) {

    // 計算尾部需要移至頭部元素個數
    k %= nums.length;

    int N = nums.length;
    int j = 0;
    int[] help = new int[nums.length];

    // 歸位區域二
    // 即歸位需要移至頭部的元素
    for (int i = N - k; i < N; i++) {
        help[j++] = nums[i];
    }

    // 歸位區域一
    // 即歸位需要移至尾部的元素
    for (int i = 0; i < N - k; i++) {
        help[j++] = nums[i];
    }

    System.arraycopy(help, 0, nums, 0, N);
}

復雜度分析

時間復雜度:O(n)。遍歷數組需要 O(n) 的時間。
空間復雜度:O(n)。需要輔助數組。

討論歸納二:輔助數組,前世今生

重點:數組元素 a[i] 通過潘多拉魔盒找到今生(a[i] 旋轉后在新的位置下標 j)

遍歷數組,找到前世 a[i] 的今生 j, 並安排到輔助數組對應的位置

魔盒:j = (i+k) % N

前世今生圖

前世今生圖

動畫模擬

前世今生動畫

示例二:輔助數組,前世今生

public void rotate(int[] nums, int k) {
    int n = nums.length;
    int[] help = new int[n];
    for (int i = 0; i < n; ++i) {
        // 旋轉 k, 相當於 nums[i] 元素向后跨步 k 個下標
        // nums 數組下標范圍是 [0, N-1]
        // 跨步后下標超過N-1,從 0 繼續跨步
        // 計算 nums[i] 旋轉后在輔助數組中的相對位置
        int m = (i + k) % n;
        help[m] = nums[i];
    }
    System.arraycopy(help, 0, nums, 0, n);
}

復雜度分析

時間復雜度:O(n)。其中 n 為數組的長度。
空間復雜度:O(n)。需要額外空間。

討論歸納三:翻轉數組

歸納一中,囧囧划分了旋轉區域,利用輔助數組實現區域旋轉,實現了數組旋轉的目的。

實際上,我們不需要借助輔助數組也能實現區域旋轉,達到交換目的。

首先還是利用模運算計算出需要轉移到數組頭部的元素個數。

在通過翻轉數組實現旋轉。

1 2 3 4 5 6 7   K=3

第一步:根據數組長度 N 和跨步 K 計算出需要轉移至數組頭部的元素個數
第二步:將數組划分為兩個區域
	注意:(邏輯區域,思想區域,這里是為了方便理解,不需要真實狀態標注)
	區域一:需要旋轉到右邊的數(頭部需要旋轉到尾部的元素)
	1 2 3 4
	
	區域二:需要旋轉到左邊的數(尾部需要旋轉到頭部的元素)
	5 6 7
	
第三步:翻轉整個數組 
	7 6 5 4 3 2 1
第四部:翻轉區域二,在翻轉區域一
	翻轉區域二   5 6 7
	翻轉區域一   1 2 3 4
	
	5 6 7 1 2 3 4	

動畫模擬

翻轉數組動畫

示例三:翻轉數組

public void rotate(int[] nums, int k) {

    // 計算尾部需要移至頭部元素個數
    k %= nums.length;

    // 翻轉數組所有元素
    reverse(nums, 0, nums.length - 1);
    // 翻轉已經移至頭部的元素
    reverse(nums, 0, k - 1);
    // 翻轉已經移至尾部的元素
    reverse(nums, k, nums.length - 1);
}

// 翻轉 [start, end] 范圍內的數
public void reverse(int[] nums, int start, int end) {
    while (start < end) {
        int temp = nums[start];
        nums[start] = nums[end];
        nums[end] = temp;
        start += 1;
        end -= 1;
    }
}

勇敢牛牛

短話長說

學算法先學什么?什么階段該刷什么題?

關注我,日常打卡算法圖解。

按照力扣題目類別結構化排序刷題,從低階到高階,圖解算法(更新中...),有興趣的童鞋,歡迎一起從小白開始零基礎刷力扣,共同進步!

短話長說

回復:678,獲取已分類好的部分刷題順序,后續內容會持續更新,感興趣的小伙伴自由拿取!

另外,有關分類,求小伙伴們不要再問我最后一類的起名了,奇技淫巧是個褒義詞,意思是指新奇的技藝和作品。

力扣修煉體系題目,題目分類及推薦刷題順序及題解

目前暫定划分為四個階段:

算法低階入門篇--武者鍛體

算法中級進階篇--武皇煉心

算法高階強化篇--武帝粹魂

算法奇技淫巧篇--戰斗秘典

以上分類原諒我有個修仙夢...

缺漏內容,正在努力整理中...

gzw


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM