leetcode題解-初級演算法陣列篇(1-5題)
7月保研的夏令營已經告一段落了,面試中被問了很多演算法的問題,感覺自己演算法知識有些許薄弱(acm大神忽略),所以準備開始刷leetcode,順便也為面試準備,因為想把刷leet裡面的一些心得給記下來,便於之後複習,所以在這裡開博。之後會按裡面的篇章順序進行更新,喜歡的可以給文章點一個贊,如果文章有任何問題或者有更好的解法可以在評論中給出,下面開始題解,本篇章為初級演算法的陣列篇(1-5題):
第一題:從排序陣列中刪除重複項
題目要求:給定一個排序陣列,你需要在原地刪除重複出現的元素,使得每個元素只出現一次,返回移除後陣列的新長度。
不要使用額外的陣列空間,你必須在原地修改輸入陣列並在使用 O(1) 額外空間的條件下完成。
演算法說明:這題是簡單題,題目中要求要用O(1)的空間複雜度,所以是不能額外建一個數組了,我的思路是建一個temp等於第一個數,再建一個res變數用於儲存不同的元素個數,因為陣列是排序的,所以對陣列進行掃描,若掃描的值和temp不一樣,則更新temp並且res++,把不一樣的元素移到對應的位置num[res-1]。
其程式碼如下:
class Solution {
public:
int removeDuplicates(vector<int>& nums) {
int res=1;
int curser;
if (nums.size()==0){
return 0;
}
int temp=nums[0];
for(int i=0;i<nums.size();i++){
if(nums[i]!=temp){
res++;
temp=nums[i];
nums[res-1]=nums[i];
}
else{
}
}
return res;
}
};
第二題:買賣股票的最佳時機 II
題目說明:給定一個數組,它的第 i 個元素是一支給定股票第 i 天的價格。設計一個演算法來計算你所能獲取的最大利潤。你可以儘可能地完成更多的交(多次買賣一支股票)。
注意:你不能同時參與多筆交易(你必須在再次購買前出售掉之前的股票)。
演算法:本題就是一題貪心,當後一天的價格比之前高就賣出,具體為什麼可以自己仔細想一想。
程式碼如下:
class Solution {
public:
int maxProfit(vector<int>& prices) {
int sum=0;
if(prices.size()==1||prices.size()==0){
return 0;
}
for(int i=0;i<prices.size()-1;i++){
if(prices[i+1]>prices[i]){
sum=sum+prices[i+1]-prices[i]; }
}
return sum;
}
};
第三題:旋轉陣列
給定一個數組,將陣列中的元素向右移動 k 個位置,其中 k 是非負數。
示例 1:
輸入: [1,2,3,4,5,6,7] 和 k = 3
輸出: [5,6,7,1,2,3,4]
解釋:
向右旋轉 1 步: [7,1,2,3,4,5,6]
向右旋轉 2 步: [6,7,1,2,3,4,5]
向右旋轉 3 步: [5,6,7,1,2,3,4]
儘可能想出更多的解決方案,至少有三種不同的方法可以解決這個問題。
要求使用空間複雜度為 O(1) 的原地演算法。
該題的解法有很多,這裡給出三種空間為O(1)的方法。
方法一:寫一個旋轉一次的函式,然後根據題目要求的k,旋轉k次,這樣空間複雜度為O(1),時間複雜度為O(N^K)。
方法二:和上個方法類似,不過移動的時候直接通過nums[i]與nums[(i+k)%nums.size()]這樣對應,從而減少操作次數。空間複雜度O(1),時間複雜度O(N)。
方法三:這是另一個比較好的方法,建立一個變數times=k%n。然後對於一個數組從times開始把整個陣列分為兩個部分。如[1,2,3,4,5,6,7] 和 k = 3,此時n=7。times=3。則把[1,2,3,4,5,6,7]分成兩個部分[1,2,3,4 | 5,6,7],然後把第一個部分翻轉[4,3,2,1 | 7,6,5],把第二部分也翻轉[4,3,2,1 | 7,6,5],最後把整個陣列翻轉得到最終答案[5,6,7,1,2,3,4],該方法時間複雜度O(n)。
該方法的程式碼如下:
class Solution {
public:
void rotate(vector<int>& nums, int k) {
int n=nums.size();
int times=k%n;
if(times==0)
return;
rotCore(nums,0,n-1-times);
rotCore(nums,n-times,n-1);
rotCore(nums,0,n-1);
}
void rotCore(vector<int>& nums,int b,int e){
while(b<e){
swap(nums[b],nums[e]);
++b;
--e;
}
return;
}
};
第四題 存在重複
題目描述:給定一個整數陣列,判斷是否存在重複元素。如果任何值在陣列中出現至少兩次,函式返回 true。如果陣列中每個元素都不相同,則返回 false。
演算法說明:這題和第一題的不同之處在於不是有序的陣列。方法1通過對每個元素判斷是否有重複,時間複雜度O(n^2)。所以這裡我採用了set容器,掃描的過程中把元素加入,如果有重複就返回true,因為set容器中的查詢為紅黑樹,所以該方法的時間複雜度為O(nlogn)。程式碼如下:
class Solution {
public:
bool containsDuplicate(vector<int>& nums) {
set<int> table;
int i;
for(i=0;i<nums.size();i++) {
if(table.count(nums[i])==1) return true;
table.insert(nums[i]);
}
return false;
}
};
第五題 只出現一次的數字
題目說明:給定一個非空整數陣列,除了某個元素只出現一次以外,其餘每個元素均出現兩次。找出那個只出現了一次的元素。
說明:你的演算法應該具有線性時間複雜度。 你可以不使用額外空間來實現嗎?
演算法說明:這道題目是面試中的原題了,有同學面試被問到過,難度在於線性時間複雜度和不使用額外空間,要滿足這兩個條件的本題的方法是使用異或。
首先我們知道異或對與一樣的兩個數他們的結果會是0,而且異或符合交換律,所以把陣列中所有的數異或一遍就得到了結果,而且符合了線性複雜度和0額外空間,其程式碼如下:
class Solution {
public:
int singleNumber(vector<int>& nums) {
int m=0;
for(int i=0;i<nums.size();i++)
m=m^nums[i];
return m;
}
};
6-11題的題解馬上也會更新