剑指offer-查找

查找包含,顺序查找,二分查找,哈希表查找和二叉排序树查找。
一. 二分查找
题目:旋转数组的最小数字
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。
例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。
思路
重点说一下二分查找法。如果是在排序的数组(或者部分排序的数组)中查找一个数字或者统计某个数字出现的次数,那么都可以尝试二分查找算法。二分查找法的精髓就在于,两个指针,一个high,一个low,通过mid来比较,然后将mid赋给high或者low。
代码

#include<iostream>
using namespace std;
int findMin(int*array,int length)
{
    int p1=0;
    int p2=length-1;
    int pmid=0;

    while(p1<p2)
    {
        if(array[p1]<array[p2])
            return array[p1];//旋转了0个数字,也就是说,是数组本身
        if(p2-p1==1)
            return array[pmid];
        pmid=((p2-p1)>>1)+p1;//特别注意,pmid=(p2-p1)>>1+p1;少一个括号是完全不一样的,或者直接写pmid=(p1+p2)/2

        if(array[pmid]>array[p1])
            p1=pmid;
        else if(array[pmid]<array[p2])
            p2=pmid;

    }
}
int main()
{
   int array[5]={3,4,5,1,2};
   cout<<findMin(array,5);
}

补充位运算

int main()
{
   int a=2,b=4;
   int c=((a+b)>>1)+1;
   int d=(a+b)>>1+1;
   cout<<c<<" "<<d<<endl;
}

上述代码,c为4,d为1.

题目:统计一个数字num在排序数组中出现的次数。
一般解法:用二分查找法去找到那个数字,然后往前往后遍历统计次数,但这种方法可能需要遍历n个元素,因此时间复杂度是O(n)。

#include<iostream>
using namespace std;
int FindNum(int*arr,int length,int num)
{
    int low=0;
    int high=length-1;
    int count=0;
    int mid=(high+low)/2;
    while(high>=low&&arr[mid]!=num)
    {
        mid=(high+low)/2;
        if(arr[mid]<num)
            low=mid;
        else if(arr[mid]>num)
            high=mid;

    }
    if(high>=low&&arr[mid]==num)
    {
        count=1;
        int temp=mid;
        while(temp-->=0)
        {

            if(arr[temp]==num)
                count++;
        }
        temp=mid;
        while(temp++<=length-1)
        {
            if(arr[temp]==num)
                count++;
        }
    }
    return count;

}
int main()
{
    int arr[9]={1,3,3,3,3,5,5,5,5};
    int res=FindNum(arr,9,5);
    cout<<res;
}

高级解法:上面那个解法慢是因为要去确定num第一次和最后一次出现的位置,因此就算使用了二分查找法还是很慢。但可以用二分查找法去确定num第一次出现的位置。用二分查找法找到一个num之后,看num前面的数是否为num,如果不是,则这个num就是第一个,否则第一个num就在前半段,二分了。

#include<iostream>
using namespace std;
int FindFirstNum(int*arr,int length,int num)
{
    int low=0;
    int high=length-1;
    int count=0;
    int mid=(high+low)/2;
    while(high>=low)
    {
        mid=(high+low)/2;
        if(arr[mid]<num)
            low=mid;
        else if(arr[mid]>num)
            high=mid;
        else if(arr[mid]==num)
        {
            if(arr[mid-1]!=num)
                return mid;
            else high=mid;
        }

    }
}
int FindLastNum(int*arr,int length,int num)
{
    int low=0;
    int high=length-1;
    int count=0;
    int mid=(high+low)/2;
    while(high>=low)
    {
        mid=(high+low)/2;
        if(arr[mid]<num)
            low=mid;
        else if(arr[mid]>num)
            high=mid;
        else if(arr[mid]==num)
        {
            if(arr[mid+1]!=num)
                return mid;
            else low=mid;
        }

    }
}
int main()
{
    int arr[9]={1,3,3,3,3,5,5,5,5};
    int first=FindFirstNum(arr,9,3);
    int last=FindLastNum(arr,9,3);
    int count=last-first+1;
    cout<<count;
}

二.哈希表查找
哈希表最主要的优点是我们利用它能够在O(1)时间内查找某一元素,是效率最高的查找方式;但其缺点是需要额外的空间来实现哈希表。
题目第一个只出现一次的字符
在一个字符串(1<=字符串长度<=10000,全部由大写字母组成)中找到第一个只出现一次的字符。

思路
处理字符串中重复或者次数出现等问题,最常用的就是哈希表,用字符串中的字符作为key,字符出现次数作为value,假定只有ASCII码范围内的字符,则可以开辟一个256大小的int数组,将每个字符(key)映射到该数组的对应位置上,计算每次出现的次数即可,遍历一次字符串,计算每个字符出现的次数,保存在int数组的对应位置上,第二次遍历字符串,若第一次出现某个字符对对应到的哈希表的对应位置处的元素为1,则该字符便是第一个只出现一次的字符,如果我们是遍历哈希表(int数组),则找到的哈希表中的第一个元素为1的位置对应的字符为字符串中第一个最小的只出现一次的字符。时间复杂度为O(n),需要额外的256个int空间来辅助,可以看做空间复杂度为O(1)。

代码

#include<iostream>
using namespace std;
char FirstNotRepeatingChar(char*str)
{
    const int N=256;//char 8bit,256种
    int hashtable[N];
    for(int i=0;i<256;++i)
        hashtable[i]=0;
    char*phashkey=str;
    while(*(phashkey)!='\0')
        hashtable[*(phashkey++)]++;
    phashkey=str;
    while(*phashkey!='\0')
      {
          if(hashtable[*phashkey]==1)
        return *phashkey;
          phashkey++;
      }

}

int main()
{
    char str[]="abbaccdffj";
    char res=FirstNotRepeatingChar(str);
    cout<<res;
}

猜你喜欢

转载自blog.csdn.net/gary_god/article/details/79637452
今日推荐