LeetCode-34. Search for a Range
阿新 • • 發佈:2018-01-23
改變 必須 條件篩選 col sea 二分法 tro 例子 spa
一、問題描述
給定一個升序排列的數組nums,和一個目標數target,找出nums中target的索引範圍。
例子:給定數組為{5, 7, 7, 8, 8, 10},target=8。返回{3,4}
二、問題解決
思路一:直接遍歷就可以,第一次碰到target的時候記錄位置1,繼續遍歷到不是target或數組尾,記錄下位置2。時間復雜度為n
vector<int> searchRange1(vector<int>& nums, int target) { vector<int> result = {-1,-1}; for(int i = 0; i < nums.size(); ++i) { if (nums[i] == target) { result[0] = i; while (i < nums.size() && nums[i] == target) i++; result[1] = i - 1; return result; } } return result; } int main() { vector<int> v = { 5,7,7,8,8,10 }; vector<int> result = searchRange(v, 8); for (auto i : result) { cout << i << endl; } system("pause"); return 0; }
思路二:使用二分查找,找到第一個target之後,向左找第一個不是target的位置或是數組頭,記錄為位置1。然後從第一個target位置向後尋找,找到第一個不是target的位置或是數組尾,記錄為位置2。這樣復雜度比第一種情況要低一些,但是和數組中和target值相等的元素個數有關系。
vector<int> searchRange(vector<int>& nums, int target) { vector<int> result = { -1,-1 }; int pos1 = 0; int pos2 = nums.size() - 1; while (pos1 <= pos2) { int middle = (pos1 + pos2) / 2; if (nums[middle] == target) { int temp = middle; while (middle >= 0&&nums[middle] == target) --middle; result[0] = middle+1; while (temp < nums.size() && nums[temp] == target) ++temp; result[1] = temp - 1; return result; } if (nums[middle] > target) pos2 = middle - 1; if (nums[middle] < target) pos1 = middle + 1; } return result; }
思路三:使用徹底的二分查找思路,能保證復雜度降到logn。先使用二分法找出左邊節點,再找出又邊節點。但是找出左右節點需要對二分法做一些修改。
vector<int> searchRange(vector<int>& nums, int target) { //總體思路,先二分法找到左端點,再二分法找到又端點 vector<int> result = {-1,-1}; //註意這裏pos2初始化為size()而不是size()-1。 int pos1 = 0; int pos2 = nums.size(); int middle = (pos1 + pos2) / 2; while (pos1 < pos2) { middle = (pos1 + pos2) / 2; //註意此處和二分法的差別,等於條件的處理是怎麽樣的 if (nums[middle] >= target) pos2 = middle ; if (nums[middle] < target) pos1 = middle + 1; } //第一個條件判斷是不是沒找到target,第二個條件篩選數組程度為1,且沒有找到的情況。 if (nums.size() == pos1 || nums[pos1] != target) return result; result[0] = pos1; //當pos1=n,pos2=n+1的時候,middle是指向n的,要找右邊的節點,就必須想辦法改變一下二分法。 pos1 = 0; pos2 = nums.size() ; middle = (pos1 + pos2) / 2; while (pos1 < pos2) { middle = (pos1 + pos2) / 2; if (nums[middle] > target) pos2 = middle; if (nums[middle] <= target) pos1 = middle +1; } //這裏需要減一 result[1] = pos1-1; return result; }
三、問題思考
第三種方法需要復習,理解二分法。
二分法需要註意的地方:
1、while循環的判斷條件贏寫成while(pos1<=pos2)而不是while(pos1<pos2),沒有等號時,當數組只有一個元素的情況會漏。在pos1=n,pos2=n+1,且target=nums[pos2]的時候也會遺漏。
2、當pos1=n,pos2=n+1時,middle會取得n,應為/2時忽略的余數,這使得選取middle會有“向左移”的傾向,思路三在找出右邊範圍的時候因此做了很多的修改。需要註意。
LeetCode-34. Search for a Range