2-27.移除元素
給你一個陣列 nums
和一個值 val
,你需要 原地 移除所有數值等於 val
的元素。元素的順序可能發生改變。然後返回 nums
中與 val
不同的元素的數量。
假設 nums
中不等於 val
的元素數量為 k
,要透過此題,您需要執行以下操作:
- 更改
nums
陣列,使nums
的前k
個元素包含不等於val
的元素。nums
的其餘元素和nums
的大小並不重要。 - 返回
k
。
使用者評測:
評測機將使用以下程式碼測試您的解決方案:
int[] nums = [...]; // 輸入陣列
int val = ...; // 要移除的值
int[] expectedNums = [...]; // 長度正確的預期答案。
// 它以不等於 val 的值排序。
int k = removeElement(nums, val); // 呼叫你的實現
assert k == expectedNums.length;
sort(nums, 0, k); // 排序 nums 的前 k 個元素
for (int i = 0; i < actualLength; i++) {
assert nums[i] == expectedNums[i];
}
如果所有的斷言都透過,你的解決方案將會 透過。
示例 1:
輸入:nums = [3,2,2,3], val = 3
輸出:2, nums = [2,2,_,_]
解釋:你的函式函式應該返回 k = 2, 並且 nums 中的前兩個元素均為 2。
你在返回的 k 個元素之外留下了什麼並不重要(因此它們並不計入評測)。
示例 2:
輸入:nums = [0,1,2,2,3,0,4,2], val = 2
輸出:5, nums = [0,1,4,0,3,_,_,_]
解釋:你的函式應該返回 k = 5,並且 nums 中的前五個元素為 0,0,1,3,4。
注意這五個元素可以任意順序返回。
你在返回的 k 個元素之外留下了什麼並不重要(因此它們並不計入評測)。
提示:
0 <= nums.length <= 100
0 <= nums[i] <= 50
0 <= val <= 100
雙指標法:使用雙指標法的重點是理解兩個指標分別在做什麼。
快指標的作用是遍歷陣列,來刪除掉特定的val值。慢指標的作用是判斷快指標指向的值是否是val並將非val的值儲存到目前所指向的位置上。當迴圈結束後,快指標會到陣列地址的末尾,但慢指標所指向的是我們所求陣列的末尾。
由於陣列的特性,在不考慮陣列後面地址的情況下已經完成了刪除操作。而此時慢指標的值就是新陣列的大小,且快指標-慢指標+1的值就是val值的數量。程式碼如下:
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
//雙指標法
int slowIndex = 0;
for(int fastIndex = 0;fastIndex < nums.size(); fastIndex++){
if(val != nums[fastIndex]){//fast先動,當fast指向的數字不為val時,就把fast指向的數字填入slow指向的位置。
nums[slowIndex++] = nums[fastIndex];
}
}
return slowIndex;//最後給出慢指標數值,也就是陣列大小即可
}
};
3-977.有序陣列的平方
給你一個按 非遞減順序 排序的整數陣列 nums
,返回 每個數字的平方 組成的新陣列,要求也按 非遞減順序 排序。
示例 1:
輸入:nums = [-4,-1,0,3,10]
輸出:[0,1,9,16,100]
解釋:平方後,陣列變為 [16,1,0,9,100]
排序後,陣列變為 [0,1,9,16,100]
示例 2:
輸入:nums = [-7,-3,2,3,11]
輸出:[4,9,9,49,121]
提示:
1 <= nums.length <= 104
-104 <= nums[i] <= 104
nums
已按 非遞減順序 排序
進階:
- 請你設計時間複雜度為
O(n)
的演算法解決本問題
由於暴力法的時間複雜度較高,根據卡哥給出的思路,嘗試雙指標法來解決問題,看了下卡哥的講解後自己嘗試寫了一下,經歷一些小改動之後也是成功ac。程式碼如下:
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
int flag = nums.size() - 1;//flag作為新陣列的指標,負責從後向前來賦值
vector<int>result(nums.size(),0);//定義一個新陣列來儲存數值
for(int i = 0,j = nums.size() - 1; i <= j;){//雙指標i和j
if((nums[i]*nums[i]) >= (nums[j]*nums[j])){
result[flag] = (nums[i]*nums[i]);
flag--;//賦值後將flag減少,並且移動左指標
i++;
}else if((nums[j]*nums[j]) > (nums[i]*nums[i])){
result[flag] = (nums[j]*nums[j]);
flag--;//賦值後將flag減少,並且移動右指標
j--;
}
}
return result;//輸出結果即可
}
};
這裡說一下我覺得比較重要的部分,首先是陣列從後向前賦值,打破了我以前的一些思維定式,這樣就會方便很多。其次,for迴圈中的最後一個語句是可以不寫的,將i++和j--寫進判斷裡面來進行迴圈,這是我之前沒考慮過的事情。
最開始寫的時候我定義了一個左指標一個右指標,然後迴圈裡面的i只是做為計數器使用,這其實會比較麻煩。
然後奇妙的地方是當左右相等的時候,其實如果前面寫大於,後面就可以直接else,因為左右相等時先放哪一個都一樣,寫大於會比我這個大於等於少打一個符號,還有就是else的問題,我這裡用了else if是因為我有點擔心會不會有其他情況導致出現問題。
但實際上和卡哥講的一樣,當小於等於的時候直接右指標賦值就可以了,也不存在其他情況,直接else可以少寫很多內容。
某些地方還是可以做一些簡化和改動,比如c++中特有的,可以把flag--寫進裡面。這裡寫進去後的含義是,執行這段語句結束後將flag--,於是有了第二版的改動程式碼:
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
int flag = nums.size() - 1;//flag作為新陣列的指標,負責從後向前來賦值
vector<int>result(nums.size(),0);//定義一個新陣列來儲存數值
for(int i = 0,j = nums.size() - 1; i <= j;){//雙指標i和j
if((nums[i]*nums[i]) > (nums[j]*nums[j])){
result[flag--] = (nums[i]*nums[i]);//賦值後將flag減少,並且移動左指標
i++;
}else{
result[flag--] = (nums[j]*nums[j]);//賦值後將flag減少,並且移動左指標
j--;
}
}
return result;//輸出結果即可
}
};
由於今天事情比較多,所以只是補上了昨天的內容,今天原本要做的內容我明天來補!一刷演算法還是希望能跟上節奏,進階題目先放一下,把每天的題目弄明白就算成功。