演算法習題(2):Leetcode初級演算法(陣列)
Leetcode初級演算法(陣列)
從排序陣列中刪除重複項
給定一個排序陣列,你需要在原地刪除重複出現的元素,使得每個元素只出現一次,返回移除後陣列的新長度。
不要使用額外的陣列空間,你必須在原地修改輸入陣列並在使用 O(1) 額外空間的條件下完成。
示例 1:
給定陣列 nums = [1,1,2],
函式應該返回新的長度 2, 並且原陣列 nums 的前兩個元素被修改為 1, 2。
你不需要考慮陣列中超出新長度後面的元素。
示例 2:
給定 nums = [0,0,1,1,1,2,2,3,3,4],
函式應該返回新的長度 5, 並且原陣列 nums 的前五個元素被修改為 0, 1, 2, 3, 4。
你不需要考慮陣列中超出新長度後面的元素。
這題很噁心,第一遍用c直接排序,刪除寫出來了,第二次的時候用c++寫,發現他沒有提供sort()和erase()(刪除任意位置)函式,不能直接寫0.0,所以具體思路和c差不多,而且他給出的test資料是已經排好序了的…..
int removeDuplicates(vector<int>& nums) {
if(nums.size()==0){
return 0;
}
int sum = 1;
for(int i=1;i<nums.size();i++){
if (nums[i]==nums[i-1]){
for(int j=i;j<nums.size();j++){
nums[j] = nums[j+1];
}
nums.pop_back();
i--;
}
else{
sum++;
}
}
return sum;
}
買賣股票的最佳時機 II
買賣股票的最佳時機
輸入一個數組,它的第 i 個元素是一支給定股票第 i 天的價格。
設計一個演算法來計算你所能獲取的最大利潤。你可以儘可能地完成更多的交易(多次買賣一支股票)。
注意:你不能同時參與多筆交易(你必須在再次購買前出售掉之前的股票)。
示例 1:
輸入: [7,1,5,3,6,4]
輸出: 7
解釋: 在第 2 天(股票價格 = 1)的時候買入,在第 3 天(股票價格 = 5)的時候賣出, 這筆交易所能獲得利潤 = 5-1 = 4 。
隨後,在第 4 天(股票價格 = 3)的時候買入,在第 5 天(股票價格 = 6)的時候賣出, 這筆交易所能獲得利潤 = 6-3 = 3 。
示例 2:
輸入: [1,2,3,4,5]
輸出: 4
解釋: 在第 1 天(股票價格 = 1)的時候買入,在第 5 天 (股票價格 =5)的時候賣出, 這筆交易所能獲得利潤 = 5-1 = 4 。
注意你不能在第 1 天和第 2 天接連購買股票,之後再將它們賣出。
因為這樣屬於同時參與了多筆交易,你必須在再次購買前出售掉之前的股票。
示例 3:
輸入: [7,6,4,3,1] 輸出: 0 解釋: 在這種情況下, 沒有交易完成, 所以最大利潤為 0。
貪心演算法,最貪心的方法就是隻要它後面的比他大,就將差值記錄下來
int maxProfit(vector<int>& prices) {
if(prices.size()==0||prices.size()==1)
return 0;
int count = 0;
for(int i=0;i<prices.size()-1;i++){
if(prices[i]<prices[i+1]){
count+=(prices[i+1]-prices[i]);
}
} //記錄差值
return count;
}
旋轉陣列
旋轉陣列
給定一個數組,將陣列中的元素向右移動 k 個位置,其中 k 是非負數。
示例 1:
輸入: [1,2,3,4,5,6,7] 和 k = 3
解釋: 向右旋轉 1 步:[7,1,2,3,4,5,6]
向右旋轉 2 步: [6,7,1,2,3,4,5]
向右旋轉 3 步: [5,6,7,1,2,3,4]
示例 2:
輸出: [3,99,-1,-100]
解釋: 向右旋轉 1 步: [99,-1,-100,3]
向右旋轉 2 步: [3,99,-1,-100]
說明:
- 儘可能想出更多的解決方案,至少有三種不同的方法可以解決這個問題。 要求使用
空間複雜度為 O(1) 的原地演算法。
maye….試了好幾遍挨個旋轉,還是不行,不過應該可以多個旋轉,2個,3個,速度比較快,0.0我沒用空間複雜度為O(1)的原地演算法,就是gan♂
void rotate(int* nums, int numsSize, int k) {
int len = numsSize;
int res[len];
int order = 0;
for(int i = len - k%len;i < len;i++){
res[order++] = nums[i];
}
for(int i = 0; i < len - k%len; i++){
res[order++] = nums[i];
}
for(int i = 0;i < len; i++){
nums[i] = res[i];
}
}
存在重複
存在重複
給定一個整數陣列,判斷是否存在重複元素。
如果任何值在陣列中出現至少兩次,函式返回 true。如果陣列中每個元素都不相同,則返回 false。
示例 1:
輸入: [1,2,3,1]
輸出: true
示例 2:
輸入: [1,2,3,4]
輸出: false
示例 3:
輸入: [1,1,1,3,3,4,3,2,4,2]
輸出: true
直接排序然後判斷是否有重複。
bool containsDuplicate(vector<int>& nums) {
int n = nums.size();
std::sort(nums.begin(),nums.end()); //排序
for(int i=0;i<n-1;i++){
if(nums[i]==nums[i+1]){
return true; //判斷
}
}
return false;
}
只出現一次的數字
只出現一次的數字
給定一個非空整數陣列,除了某個元素只出現一次以外,其餘每個元素均出現兩次。找出那個只出現了一次的元素。
給定一個非空整數陣列,除了某個元素只出現一次以外,其餘每個元素均出現兩次。找出那個只出現了一次的元素。
說明:
你的演算法應該具有線性時間複雜度。 你可以不使用額外空間來實現嗎?
示例 1:
輸入: [2,2,1]
輸出: 1
示例 2:
輸入: [4,1,2,1,2]
輸出: 4
emmmmmmm先進行排序,然後判斷第一位和末位是否重複,再將每一個與其前後比較判斷(可以有更簡單的方法)
int singleNumber(vector<int>& nums) {
std::sort(nums.begin(),nums.end()); //排序
if(nums[0]!=nums[1]){
return nums[0];
}
if(nums[nums.size()-2]!=nums[nums.size()-1]){
return nums[nums.size()-1];
} //判斷首尾
for(int i=1;i<nums.size()-1;i++){
if(nums[i]!=nums[i+1]&&nums[i]!=nums[i-1]){
return nums[i]; //比較前後
}
}
}
兩個陣列的交集 II
兩個陣列的交集 II
給定兩個陣列,寫一個方法來計算它們的交集。
例如:
給定 nums1 = [1, 2, 2, 1], nums2 = [2, 2], 返回 [2, 2].
注意:
- 輸出結果中每個元素出現的次數,應與元素在兩個陣列中出現的次數一致。
- 我們可以不考慮輸出結果的順序。
跟進:
- 如果給定的陣列已經排好序呢?你將如何優化你的演算法?
- 如果 nums1 的大小比 nums2 小很多,哪種方法更優?
- 如果nums2的元素儲存在磁碟上,記憶體是有限的,你不能一次載入所有的元素到記憶體中,你該怎麼辦?
剛看到這道題的時候沒有什麼頭緒,最後想了一下,陣列先排序咋樣都不錯0.0,然後將陣列排序,然後從小到大如果nums1的值大,nums2的節點就往後,如果nums2的值大,nums1的節點就往後,如果相等則將數填入新的數組裡,最後返回動態陣列。
vector<int> intersect(vector<int>& nums1, vector<int>& nums2) {
std::sort(nums1.begin(),nums1.end());
std::sort(nums2.begin(),nums2.end()); //排序
vector<int> a;
int i = 0;
int j = 0;
while(i<nums1.size()&&j<nums2.size()){
if(nums1[i]>nums2[j]){
j++;
}
else if(nums1[i]<nums2[j]){
i++;
} //判斷
else{
a.push_back(nums1[i]);
i++;
j++; //填入
}
}
return a; //返回
}
加一
加一
給定一個非負整數組成的非空陣列,在該數的基礎上加一,返回一個新的陣列。
最高位數字存放在陣列的首位, 陣列中每個元素只儲存一個數字。
你可以假設除了整數 0 之外,這個整數不會以零開頭。
示例 1:
輸入: [1,2,3]
輸出: [1,2,4]
解釋: 輸入陣列表示數字 123。
示例 2:
輸入: [4,3,2,1]
輸出: [4,3,2,2]
解釋: 輸入陣列表示數字 4321。
emmmmmmm先reverse給首位加1,然後判斷有沒有進位,最後一位要是進位了再補個1,最後再reverse回來
vector<int> plusOne(vector<int>& digits) {
reverse(digits.begin(), digits.end()); //反轉
digits[0]++; //加1
for(int i=0;i<digits.size()-1;i++){
if(digits[i]==10){
digits[i+1]++;
digits[i]=0; 判斷進位
}
}
if(digits[digits.size()-1]==10){
digits[digits.size()-1]=0; //判斷末位是否進位
digits.push_back(1);
}
reverse(digits.begin(), digits.end()); //反轉
return digits; //返回
}
移動零
移動零
給定一個數組 nums,編寫一個函式將所有 0 移動到陣列的末尾,同時保持非零元素的相對順序。
示例:
輸入: [0,1,0,3,12]
輸出: [1,3,12,0,0]
說明:
- 必須在原陣列上操作,不能拷貝額外的陣列。
- 儘量減少操作次數。
遍歷,見到0將後面的全部進位,並記錄下0的個數,最後補0
void moveZeroes(vector<int>& nums) {
int sum = 0;
for(int i=0;i<nums.size();i++){
if(nums[i]==0){
for(int j=i;j<nums.size()-1;j++){
nums[j] = nums[j+1];
} //找0進位
sum++;
nums.pop_back();
i--;
}
}
for(int i=0;i<sum;i++){
nums.push_back(0); //補0
}
printf("[");
for(int i=0;i<nums.size()-1;i++){
printf("%d,",nums[i]);
}
printf("%d]",nums[nums.size()-1]);
}
兩數之和
兩數之和
給定一個整數陣列和一個目標值,找出陣列中和為目標值的兩個數。
你可以假設每個輸入只對應一種答案,且同樣的元素不能被重複利用。
示例:
給定 nums = [2, 7, 11, 15], target = 9
因為 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [0, 1]
暴力破解0.0遍歷maye 誰能告訴我個可以裝x的演算法0.0
vector<int> twoSum(vector<int>& nums, int target) {
int a,b;
for(int i=0;i<nums.size();i++){
for(int j=i+1;j<nums.size();j++){
if(nums[i]+nums[j]==target){
a = i;
b = j;
break;
}
}
}
vector<int> c;
c.push_back(a);
c.push_back(b);
return c;
}
有效的數獨
判斷一個 9x9 的數獨是否有效。只需要根據以下規則,驗證已經填入的數字是否有效即可。
- 數字 1-9 在每一行只能出現一次。
- 數字 1-9 在每一列只能出現一次。
上圖是一個部分填充的有效的數獨。
示例 1:
輸入:
[
[“5”,”3”,”.”,”.”,”7”,”.”,”.”,”.”,”.”],
[“6”,”.”,”.”,”1”,”9”,”5”,”.”,”.”,”.”],
[“.”,”9”,”8”,”.”,”.”,”.”,”.”,”6”,”.”],
[“8”,”.”,”.”,”.”,”6”,”.”,”.”,”.”,”3”],
[“4”,”.”,”.”,”8”,”.”,”3”,”.”,”.”,”1”],
[“7”,”.”,”.”,”.”,”2”,”.”,”.”,”.”,”6”],
[“.”,”6”,”.”,”.”,”.”,”.”,”2”,”8”,”.”],
[“.”,”.”,”.”,”4”,”1”,”9”,”.”,”.”,”5”],
[“.”,”.”,”.”,”.”,”8”,”.”,”.”,”7”,”9”]
]
輸出: true
示例 2:
輸入:
[
[“8”,”3”,”.”,”.”,”7”,”.”,”.”,”.”,”.”],
[“6”,”.”,”.”,”1”,”9”,”5”,”.”,”.”,”.”],
[“.”,”9”,”8”,”.”,”.”,”.”,”.”,”6”,”.”],
[“8”,”.”,”.”,”.”,”6”,”.”,”.”,”.”,”3”],
[“4”,”.”,”.”,”8”,”.”,”3”,”.”,”.”,”1”],
[“7”,”.”,”.”,”.”,”2”,”.”,”.”,”.”,”6”],
[“.”,”6”,”.”,”.”,”.”,”.”,”2”,”8”,”.”],
[“.”,”.”,”.”,”4”,”1”,”9”,”.”,”.”,”5”],
[“.”,”.”,”.”,”.”,”8”,”.”,”.”,”7”,”9”]
]
輸出: false
解釋: 除了第一行的第一個數字從 5 改為 8 以外,空格內其他數字均與 示例1 相同。
但由於位於左上角的 3x3 宮內有兩個 8 存在, 因此這個數獨是無效的。
數獨部分空格內已填入了數字,空白格用 ‘.’ 表示。
說明:
- 一個有效的數獨(部分已被填充)不一定是可解的。
- 只需要根據以上規則,驗證已經填入的數字是否有效即可。
- 給定數獨序列只包含數字 1-9
- 和字元 ‘.’ 。 給定數獨永遠是 9x9 形式的。
暫時不會0.0
旋轉影象
給定一個 n × n 的二維矩陣表示一個影象。
將影象順時針旋轉 90 度。
說明:
你必須在原地旋轉影象,這意味著你需要直接修改輸入的二維矩陣。請不要使用另一個矩陣來旋轉影象。
示例 1:
給定 matrix =
[
[1,2,3],
[4,5,6],
[7,8,9]
],原地旋轉輸入矩陣,使其變為:
[
[7,4,1],
[8,5,2],
[9,6,3]
]
示例 2:
給定 matrix =
[
[ 5, 1, 9,11],
[ 2, 4, 8,10],
[13, 3, 6, 7],
[15,14,12,16]
],原地旋轉輸入矩陣,
使其變為:
[
[15,13, 2, 5],
[14, 3, 4, 1],
[12, 6, 8, 9],
[16, 7,10,11]
]
我第一想法是在while迴圈中套for迴圈,和陣列順時針輸出差不多,但我寫的時候發現,這樣寫迴圈條件很難找,我也沒找到,你觀察這個陣列,先將陣列轉置,再將每一行reverse,就是旋轉好的陣列了,所以程式碼(但這樣寫和題目不符,明天我在來更新第二種寫法):
第一種寫法:
void rotate(vector<vector<int>>& matrix) {
vector<vector<int>> a(matrix.size());
int k=0;
for(int j=0;j<matrix[0].size();j++){
for(int i=0;i<matrix.size();i++){
a[k].push_back(matrix[i][j]);
}
k++;
} //轉置
for(int i=0;i<a.size();i++){
reverse(a[i].begin(),a[i].end());
} //reverse
matrix = a; //再放到matrix上
}