給定一個整數型別的陣列 nums,請編寫一個能夠返回陣列 “中心索引” 的方法。
我們是這樣定義陣列 中心索引 的:陣列中心索引的左側所有元素相加的和等於右側所有元素相加的和。
如果陣列不存在中心索引,那麼我們應該返回 -1。如果陣列有多箇中心索引,那麼我們應該返回最靠近左邊的那一個。
示例 1:
輸入:
nums = [1, 7, 3, 6, 5, 6]
輸出:3
解釋:
索引 3 (nums[3] = 6) 的左側數之和 (1 + 7 + 3 = 11),與右側數之和 (5 + 6 = 11) 相等。
同時, 3 也是第一個符合要求的中心索引。
示例 2:
輸入:
nums = [1, 2, 3]
輸出:-1
解釋:
陣列中不存在滿足此條件的中心索引。
說明:
nums
的長度範圍為[0, 10000]
。- 任何一個
nums[i]
將會是一個範圍在[-1000, 1000]
的整數。
方法:字首和
唯一要思考的地方是如何減少計算量,如果每一箇中心時都要左右全部計算sum
一次會超時,觀察中間遊標i
的移動,當我們知道元素總和與i
左側元素的和時,右邊元素的和用減法就能得到,無需再次迴圈計算。
演算法:
S
是陣列的和,當索引i
是中心索引時,位於i
左邊陣列元素的和leftsum
滿足S - nums[i] - leftsum
。- 我們只需要判斷當前索引
i
是否滿足leftsum==S-nums[i]-leftsum
並動態計算leftsum
的值。
class Solution {
public:
int pivotIndex(vector<int>& nums) {
int S=accumulate(nums.begin(),nums.end(),0);
for(int i=0,leftsum=0;i<nums.size();i++ ){
if(leftsum==S-nums[i]-leftsum)return i;
leftsum=sum+nums[i];
}
return -1;
}
};
這個題比較奇怪,中心索引可以取到邊界,所以要先判斷再求和。因為leftsum
可以沒有元素,但最多有nums.size()-1
個元素相加。
複雜度分析
- 時間複雜度:O(N)O(N),其中 NN 是
nums
的長度。 - 空間複雜度:O(1)O(1),使用了
S
和leftsum
。
accumulate函式
accumulate
定義在#include<numeric>
中,作用有兩個,一個是累加求和,另一個是自定義型別資料的處理。accumulate
帶有三個形參:頭兩個形參指定要累加的元素範圍,第三個形參則是累加的初值。accumulate
函式將它的一個內部變數設定為指定的初始值,然後在此初值上累加輸入範圍內所有元素的值。accumulate
演算法返回累加的結果,其返回型別就是其第三個實參的型別。
搜尋插入位置
給定一個排序陣列和一個目標值,在陣列中找到目標值,並返回其索引。如果目標值不存在於陣列中,返回它將會被按順序插入的位置。你可以假設陣列中無重複元素。
示例 1:
輸入: [1,3,5,6], 5
輸出: 2
示例 2:
輸入: [1,3,5,6], 2
輸出: 1
示例 3:
輸入: [1,3,5,6], 7
輸出: 4
示例 4:
輸入: [1,3,5,6], 0
輸出: 0
思路2:在迴圈體內部排除元素( leetcode-cn.com/problems/search-in... 轉自@liweiwei1419)
while(left < right)
這種寫法表示在迴圈體內部排除元素;- 退出迴圈的時候
left
和right
重合,區間[left, right]
只剩下 1 個元素,這個元素 有可能 就是我們要找的元素。
第 2 種思路可以歸納為「左右邊界向中間走,兩邊夾」,這種思路在解決複雜問題的時候,可以使得思考的過程變得簡單。
思路分析:
首先,插入位置有可能在陣列的末尾(題目中的示例 3),需要單獨判斷。如果在陣列的末尾,插入位置的下標就是陣列的長度;
否則,根據示例和暴力解法的分析,插入位置的下標是 大於等於 target
的第 11 個元素的位置。
因此,嚴格小於 target
的元素一定不是解,在迴圈體中將左右邊界 left
和 right
逐漸向中間靠攏,最後 left
和 right
相遇,則找到了插入元素的位置。根據這個思路,可以寫出如下程式碼。
class Solution {
public:
int searchInsert(vector<int> &nums, int target) {
int size = nums.size();
if (size == 0) {
return 0;
}
// 特判
if (nums[size - 1] < target) {
return size;
}
int left = 0;
int right = size - 1;
while (left < right) {
int mid = left + (right - left) / 2;
// 嚴格小於 target 的元素一定不是解
if (nums[mid] < target) {
// 下一輪搜尋區間是 [mid + 1, right]
left = mid + 1;
} else {
// 下一輪搜尋區間是 [left, mid]
right = mid;
}
}
return left;
}
};
我自己的思考:
當最後剩兩個元素時,mid就是left。若target<=nums[mid],那麼縮小區間為[left,legt],若left是要找的,則返回left就是所需的,若不是要找的,因為left所在的元素是大於等於target的,所以要插入的位置就是left。若target>nums[mid],則縮小區間為[right,right],若right是要找的,則返回right就是所需的,若不是要找的,怎麼能保證right所在元素一定大於等於target呢?因為一開始對nums陣列的末端元素進行了判斷,所以target一定是小於等於末端元素的。當這最後兩個元素區間是末端兩個自然滿足,而當是中間的元素時,再縮排到兩個元素前,有滿足target小於nums[mid],而縮排區間後mid變為right,也就是target一定小於縮排區間後的right,所以返回的right就是要插入的位置。
複雜度分析:
- 時間複雜度:O(\log N)O(logN),這裡 NN 是陣列的長度,每一次都將問題的規模縮減為原來的一半,因此時間複雜度是對數級別的;
- 空間複雜度:O(1)O(1),使用到常數個臨時變數。
給出一個區間的集合,請合併所有重疊的區間。
示例 1:
輸入: intervals = [[1,3],[2,6],[8,10],[15,18]]
輸出: [[1,6],[8,10],[15,18]]
解釋: 區間 [1,3] 和 [2,6] 重疊, 將它們合併為 [1,6].
示例 2:
輸入: intervals = [[1,4],[4,5]]
輸出: [[1,5]]
解釋: 區間 [1,4] 和 [4,5] 可被視為重疊區間。
注意:輸入型別已於2019年4月15日更改。 請重置預設程式碼定義以獲取新方法簽名。
提示:
- intervals[i][0] <= intervals[i][1]
方法一:排序
思路
如果我們按照區間的左端點排序,那麼在排完序的列表中,可以合併的區間一定是連續的。如下圖所示,標記為藍色、黃色和綠色的區間分別可以合併成一個大區間,它們在排完序的列表中是連續的:
演算法
我們用陣列 merged 儲存最終的答案。
首先,我們將列表中的區間按照左端點升序排序。然後我們將第一個區間加入 merged 陣列中,並按順序依次考慮之後的每個區間:
如果當前區間的左端點在陣列 merged 中最後一個區間的右端點之後,那麼它們不會重合,我們可以直接將這個區間加入陣列 merged 的末尾;
否則,它們重合,我們需要用當前區間的右端點更新陣列 merged 中最後一個區間的右端點,將其置為二者的較大值。
class Solution {
public:
vector<vector<int>> merge(vector<vector<int>>& intervals) {
if (intervals.size() == 0) {
return {};
}
sort(intervals.begin(), intervals.end());
vector<vector<int>> merged;
for (int i = 0; i < intervals.size(); ++i) {
int L = intervals[i][0], R = intervals[i][1];
if (!merged.size() || merged.back()[1] < L) {
merged.push_back({L, R});
}
else {
merged.back()[1] = max(merged.back()[1], R);
}
}
return merged;
}
};
總結:
- 沒有對空的vector進行判斷而溢位錯誤,對每道題應該都進行空判,因為返回型別是vector,所以
return {};
- 排序vector只是保證了每個元素左端是從小到大的,而右端可能不是,比如[1,3]和[2,4],合併後應該是[1,4],所以右端應該是取
max(merged.back()[1], R)
。 - 題解裡直接在if里加入或條件
!merged.size()
,相當於在merged為空時對他第一次填充,免去了在外面進行第一步的操作,更簡潔。 sort(intervals.begin(), intervals.end());
,sort函式對於二維陣列,預設是按第一列進行行排列的。`
本作品採用《CC 協議》,轉載必須註明作者和本文連結