首頁 > 軟體

C語言雙指標多方法旋轉陣列解題LeetCode

2022-02-15 10:02:40

LeetCode題目如下:

首先這個中等難度我是沒搞懂,後面才發現原來中等中在要求多方法上,那就來看看怎麼搞定他吧。

暴力思路

首先我說一下我本人的思路,就是函數進行倒序操作,分三步:

1.整體倒序 :1234567-------7654321

2.前半部分倒序:7654321------- 5674321

3.後半部分倒序:5674321-------5671234

由於題目已經給出了我們 k 的值,我們直接暴力思路(注意是暴力思路非暴力求解),雙指標交換對應的值就行:

void exchange(int* a, int* b)
{
int n=*a;
*a = *b;
*b = n;
}   //交換a,b位置
void reverse(int* nums,int left,int right)
{
while(left<right)
{
exchange(&nums[left],&nums[right]);
left++;
right--;
}   //對指定範圍內元素進行翻轉操作
}
void rotate(int* nums, int numsSize, int k){
k%=numsSize;
if(k==0)
{
return ;  //防止k過大或0導致無意義操作
}
reverse(nums,0,numsSize-1);//全倒序
reverse(nums,0,k-1);//前半部分倒序
reverse(nums,k,numsSize-1);//後半部分倒序
}

這種方法直觀,最容易想到,特點是思路清晰,完美符合了流程,時間複雜度是O(n),空間複雜度是O(1),將將就就

外加陣列

自力更生不想要咱就尋求外援嘛,直接建立一個額外陣列,前半部分放前面,後半部分放後面不就行了,用 numsSize 表示陣列的長度,我們遍歷原陣列,將原陣列下標為 n 的元素放至新陣列下標為 n+k 的位置,最後將新陣列拷貝至原陣列即可:

void rotate(int* nums, int numsSize, int k){
int arr[numsSize] = {0};
for(int n = 0;n<numsSize;n++)
{
arr[(k+n)%numsSize] = nums[n]; //nums所有元素向前移動 k 個單位,依次存到陣列arr
}
for(int n = 0;n<numsSize;n++)
{
nums[n] = arr[n];  //將arr陣列內容拷貝回原陣列nums
}

同理,我們可以選擇直接 malloc 一塊空間出來,這種方法同上不贅述

格局擡高

既然我們能想到 malloc 開闢空間操作,那再想想庫函數裡面好像還有個好東西叫 memcpy ,標頭檔案:#include <string.h>,memcpy() 用來複制記憶體,且忽略 ,其原型為:

  void * memcpy ( void * dest, const void * src, size_t num );

memcpy() 會複製 src 所指的記憶體內容的前 num 個位元組到 dest 所指的記憶體地址上。memcpy() 並不關心被複制的資料型別,只是逐位元組地進行復制,這給函數的使用帶來了很大的靈活性,可以面向任何資料型別進行復制。

程式碼如下:

void rotate(int* nums, int numsSize, int k){
int arr[numsSize];
k %= numsSize;
memcpy(arr,nums+(numsSize-k),k*(int)sizeof(int));
memcpy(arr+k,nums,(numsSize-k)*(int)sizeof(int));
memcpy(nums,arr,numsSize*(int)sizeof(int));
}

但是在重疊記憶體塊這方面,memmove() 是比 memcpy() 更安全的方法,所以可能會有一個疑問就是為什麼不用 memmove?

memmove 相比 memcpy 更容易造成資料丟失。如果目標區域和源區域有重疊的話,memmove() 能保證源串在被覆蓋之前將重疊區域的位元組拷貝到目標區域中,複製後源區域的內容會被更改。如果目標區域與源區域沒有重疊,則和 memcpy() 函數功能相同。

強調一下,與 strcpy() 不同的是,memcpy() 會完整的複製 num 個位元組,不會因為遇到“”而結束。

環形替代

這是力扣上官方給出的一種方法,需要數學推導,比較難理解,解析給的是花裡胡哨,添油加醋的,我大概概括一下就是把陣列一串元素類比成莫比烏斯環,我們構圖理解就簡單多了(ppt手繪勿噴):

什麼意思呢,就是我們就拿k作為遍歷間隔,不斷拿 1+nk(n從0開始) 位置的元素替代 1+ (n+1)k位置元素,直到回到原點,回到原點時因為遍歷間隔>0,必定會有未遍歷的元素我們只需+1 跳到下一位置繼續上述操作,再使用另一單獨變數,跟蹤當前已經存取的元素數量,當該變數 = 元素數量時遍歷完成,結束遍歷過程。(個人理解,如有不當請聯絡我更正喲~)

int gcd(int a, int b) {
    return b ? gcd(b, a % b) : a;
}
void swap(int* a, int* b) {
    int t = *a;
    *a = *b, *b = t;
}
void rotate(int* nums, int numsSize, int k) {
    k = k % numsSize;
    int count = gcd(k, numsSize);
    for (int start = 0; start < count; ++start) {
        int current = start;
        int prev = nums[start];
        do {
            int next = (current + k) % numsSize;
            swap(&nums[next], &prev);
            current = next;
        } while (start != current);
    }
}

今天就到這裡吧,摸了家人們,更多關於多方法超度旋轉陣列的資料請關注it145.com其它相關文章!


IT145.com E-mail:sddin#qq.com