1. 程式人生 > 其它 >在leetcode題庫上的移除元素問題

在leetcode題庫上的移除元素問題

今天剛寫了一道leetcode上的題,覺得這題的解題思維真的是太棒了。

希望能分享給大家

先看題:

1.給你一個數組 nums和一個值 val,你需要 原地 移除所有數值等於val的元素,並返回移除後陣列的新長度。

不要使用額外的陣列空間,你必須僅使用 O(1) 額外空間原地 修改輸入陣列,限時間複雜度O(n)

元素的順序可以改變。你不需要考慮陣列中超出新長度後面的元素。

請在下面函式作答:

intremoveElement(int*nums,intnumsSize,intval) {   //語句塊
} 來源:力扣(LeetCode)連結:https://leetcode-cn.com/problems/remove-element

先說一下,這些刷題網大致是分兩種的,一種是直接給你一個函式介面,你只需要完成函式介面部分即可;(今天這題是這種)

另一種是什麼都沒有,你必須自己寫出完整的c程式碼,也就是從main函式開始寫,標頭檔案都要自己引用;


首先,我們來分析一下題目的意思:

  1. nums中可能有任意多的數,且不都相同,你需要在nums中找到一個或多個val的值,然後原地刪除;
  2. 不能用額外的陣列,如果可以使用的話,就有一種比較簡單的方法;
  3. 空間複雜度為O(1),時間複雜度O(n)就意味著你不能使用像順序表刪除元素一樣,找到val值,就開始刪除,刪除的過程就是將val值用後一個數往前覆蓋,如此下來時間複雜度就會有O(n2)
  4. 原地刪除舉個例子:在[ 1,2,1,5,4] 中刪掉所有的1,你可以刪成這樣[ 2,5,4,0,0] 或者[ 2,5,4,1,1]我們不需要關係4後面的數是多少,只要陣列前面是2,4,5的排列組合就算完成任務;

先介紹一下用額外陣列的方法,因為我們可以從這個方法過渡到一種非常神奇的思想:

圖一:自己建立一個數組,並個給定要刪除的值,並給出刪除方法

圖二:判斷元素,不是刪除的數,放入新建陣列中,依次判斷

圖三:當判斷到有刪除數時,不放入新建陣列

圖四:判斷完後,得到的新建陣列

總結:這個方法雖然時間複雜度是滿足要求O(n),但是空間複雜度不滿足,實際上空間複雜度也是O(n)


接下來就是非常神奇的思想的講解,如何即不建立陣列又把時間複雜度控制在O(n)內:

假設我們開始有兩個不同顏色的標記,nums陣列跟val值都跟上面假設一致

圖五:準備兩個指標均指向首地址

接下來就是這個思想的過程:

圖六:前三個都是資料不變,到了第四步,指向了被刪除的數,黃色不動,黑走

圖七:看圖就明白了圖八:看圖就明白了

至此,我們就完成了不用額外陣列也可以完成刪除我們所要選的資料,且都滿足了空間複雜度為O(1),時間複雜度O(n)

剛開始、現在刪除完、之前新建陣列刪完的對比:

圖九:對比結果

那問題又來了,那該如何解決訪問到倒數第二個5就停止訪問呢?

其實很簡單,記錄下每次黑色遇到val值 2就可以了

那就我們直接上程式碼吧

 1 int removeElement(int* nums, int numsSize, int val)
 2 {
 3     int* p1 = nums;//黑色標記
 4     int* p2 = nums;//黃色標記
 5     int count = 0;//記錄下每次黑色遇到val值
 6     while (p1 < nums + numsSize)//黑色指到最後一個元素的下一個元素就停下
 7     {
 8         if (*(p1) != val)//不是val,存入黃色標記處
 9         {
10             *(p2) = *(p1);
11             p2++;//黃色標記向後加一
12         }
13         else//是val記錄
14         {
15             count++;
16         }
17         p1++;//黑色標記向後加一
18     }
19     return numsSize -  count;//返回總大小 - val出現的次數
20 }
21 #include <stdio.h>
22 int main()//測試
23 {
24     int arr[] = { 3,1,6,3,5,3,7 };
25     int sz = sizeof(arr) / sizeof(arr[0]);
26     int ret = removeElement(arr, sz, 3);
27     printf("%d ", ret);
28     return 0;
29 }

執行結果:

跟我們的預期結果一致;

(注:只要前四個是1 , 6 , 5 , 7 的排列組合就可以了)

總結:這個方法本質來講就是用雙指標來解決問題,如果想了解更多可以到leetcode的官網去看看更多大神的操作;


更新

2022-03-05

12:05:01