zoukankan      html  css  js  c++  java
  • [array] leetcode

    leetcode - 33. Search in Rotated Sorted Array - Medium

    descrition

    Suppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand.

    (i.e., 0 1 2 4 5 6 7 might become 4 5 6 7 0 1 2).

    You are given a target value to search. If found in the array return its index, otherwise return -1.

    You may assume no duplicate exists in the array.

    解析

    两种方法的时间复杂度和空间复杂度都是一样的,不过思考的思路有所不同,不过根本都是对二分查找的改进。方法 1 对应代码 int searchDirectly(vector& nums, int target); 方法 2 对应 int searchAssist(vector& nums, int target)。虽然 方法 2 对应的代码量要大一些,但思路还是值得借鉴的,这里也一并给出。

    注意点:

    • 当 target 找不到的时候返回 -1
    • 可以假设数组中的元素都是唯一的 (这是代码优化的关键!)

    一般的:

    直接在原数组上进行二分查找。对于数组 arry[0,...,n-1] 可以将其分成两个部分 left_part = arry[0,...,imax], right_part=arry[imax+1, ..., n-1],其中 imax 指向数组中最大的元素,那么 left_part 和 right_part 都是递增的,并且 left_part 中所有的值都大于 right_part 中的值。

    对于 binary search,假设 [ileft, ... , irigt] 确定 arry 中的一个子数组。下面就讨论,我们如何在每次查找中将查找空间减少一半的思路。

    每次而分查找我们需要计算 imid = (ileft + iright) / 2,即中间元素的位置,将数组均分成两半。这时我们可以根据 imid 的位置来确定下一次的查找范围。

    • condition1: 如果 arry[ileft] < arry[imid] : 说明 imid 在 left_part 的 ascending 子数组中
    • condition2: 如果 arry[imid] < arry[irigh] : 说明 imid 在 rigt_part 的 ascending 子数组中

    注意:因为 left_part < right_part ,因此以上两种情况是对立的。如果 ileft, imid, iright 指向的 3 个数相等,我们将无法判断 imid 处在数组的那个部分,也就无法达到划分的目的,这是题意的关键优化点。

    方法 1

    • 如果 condition1 成立,那么 [ileft, ..., imid] 是递增有序的
      • 如果 target 在 [ileft, ..., imid] 区间内,则 ileft = imid-1
      • 否则 ileft = imid + 1
    • 如果 condition2 成立,那么 [imid, ..., iright] 是递增有序的
      • 如果 target 在 [imid, ..., iright] 区间内,则 ileft = imid + 1
      • 否则 iright = imid - 1

    每一次查找都能使搜索空间减半。具体实现看代码,注意细节和边界条件。

    方法 2

    1. 我们可以先找到数组中最小值的位置 imin,那么相对于原来递增有序的数,新的 rotated 数组中元素的位置 i' = (i + imin)%n。比如 4 5 6 7 0 1 2, imin = 4,相当于原数组 0 1 2 4 5 6 7 循环右移了 imin 步。找最小值的位置也是使用折半查找的思想,时间复杂度 O(log(n))。
    2. 针对原数组 0 1 2 4 5 6 7 使用而分查找,每次而分查找比较时,使用 i' = (i + imin)%n 计算真是的 middle 位置。这样可以达到减办的效果。时间复杂度 O(log(n)) 。

    具体实现查看代码。虽然这样的方法比钱前一种方法来说代码量大,实际上做了两次而分查找,但这里新地址的映射方式是个很好的思考思路。

    code

    
    #include <iostream>
    #include <vector>
    #include <algorithm>
    
    using namespace std;
    
    class Solution{
    public:
    	int search(vector<int>& nums, int target){
    		// You may assume no duplicate exists in the array.
    		//return searchDirectly(nums, target);
    		return searchAssist(nums, target);
    	}
    
    	// time-O(log(n)), space-O(1)
    	int searchDirectly(vector<int>& nums, int target){
    		int ileft = 0;
    		int iright = nums.size()-1;
    		while(ileft <= iright){
    			int imid = (ileft+iright)/2;
    			if(nums[imid] == target){
    				return imid;
    			}
    
    			// nums[imid] != target
    			if(nums[ileft] <= nums[imid]){
    				// nums[ileft,...,imid] is ascending
    				// Note: don't forget to check nums[ileft] == target
    				if(nums[ileft] <= target && target < nums[imid]){
    					iright = imid - 1;
    				}else{
    					ileft = imid + 1;
    				}
    
    			}else{
    				// nums[imid] < nums[iright]
    				// nums[imid,...,iright] is ascending
    				// Note: don't forget to check target == nums[iright]
    				if(nums[imid] < target && target <= nums[iright]){
    					ileft = imid + 1;
    				}else{
    					iright = imid - 1;
    				}
    			}
    			
    		}
    
    		return -1;
    	}
    
    	// time-O(log(n)), space-O(1)
    	int searchAssist(vector<int>& nums, int target){
    		if(nums.empty())
    			return -1;
    
    		// the number of rotated of each element in nums
    		int irotated = findMinInRotatedArray(nums);
    		int n = nums.size();
    
    		int ileft = 0;
    		int iright = nums.size() - 1;
    		while(ileft <= iright){
    			int imid = (ileft + iright) / 2;
    			int imidReal = (imid + irotated) % n; // calculate the real index of middle value
    			if(nums[imidReal] == target){
    				return imidReal;
    			}else if (nums[imidReal] < target){
    				ileft = imid + 1;
    			}else{
    				// nums[imidReal] > target
    				iright = imid - 1;
    			}
    		}
    
    		return -1;
    	}
    
    	int findMinInRotatedArray(vector<int>& nums){
    		if(nums.empty())
    			return -1;
    		if(nums[0] < nums[nums.size()-1]) // nums in ascending
    			return 0;
    
    		// binary search
    		int ileft = 0; 
    		int iright = nums.size() - 1;
    		while(ileft+1 < iright){
    			int imid = (ileft + iright) / 2;
    			if(nums[ileft] < nums[imid]){
    				ileft = imid;
    			}else{
    				// nums[imid] < nums[iright]
    				iright = imid;
    			}
    		}
    
    		// ileft point to the maximum
    		// iright point to the minimum
    
    		return iright;
    	}
    };
    
    int main()
    {
    	return 0;
    }
    
    
    
  • 相关阅读:
    ICMPv6 Type 和 rfc
    Redis学习
    Vue学习(一)
    《一线架构师实践指南》读后感(五)
    《一线架构师实践指南》读后感(四)
    Stream流
    泛型
    《架构漫谈》读后感
    《一线架构师实践指南》读后感(三)
    《一线架构师实践指南》读后感(二)
  • 原文地址:https://www.cnblogs.com/fanling999/p/7841528.html
Copyright © 2011-2022 走看看