牛客网算法学习记录-二分搜索

来源:互联网 发布:linux 修改可见密码 编辑:程序博客网 时间:2024/05/22 19:57

定义局部最小的概念。arr长度为1时,arr[0]是局部最小。arr的长度为N(N>1)时,如果arr[0]<arr[1],那么arr[0]是局部最小;如果arr[N-1]<arr[N-2],那么arr[N-1]是局部最小;如果0<i<N-1,既有arr[i]<arr[i-1]又有arr[i]<arr[i+1],那么arr[i]是局部最小。 给定无序数组arr,已知arr中任意两个相邻的数都不相等,写一个函数,只需返回arr中任意一个局部最小出现的位置即可。


题意就是存在一个极小值,找到它。

int getLessIndex(vector<int> arr)
    {
        if(arr.empty())
            return -1;
        if(arr.size()==1||arr[0]<arr[1])
            return 0;
        if(arr[arr.size()-1]<arr[arr.size()-2])
            return arr.size()-1;
        int low=0,high=arr.size()-1,mid,res;
        while(low<=high)
        {
            mid=low+(high-low)/2;
            if(arr[mid]<arr[mid+1]&&arr[mid]<arr[mid-1]) //不用担心数组如果是单调递增导致数组越界的情况, 前面已经处理过单侧数组的情况了。
            {
                res=mid;
                break;
            }
            if(arr[mid]>arr[mid-1])
                high=mid-1;
            else
                low=mid+1;
        }
        return res;
    }


对于一个有序数组arr,再给定一个整数num,请在arr中找到num这个数出现的最左边的位置。

给定一个数组arr及它的大小n,同时给定num。请返回所求位置。若该元素在数组中未出现,请返回-1。

测试样例:
[1,2,3,3,4],5,3
返回:2

二分搜索:

int findPos(vector<int> arr, int n, int num) {
        // write code here
        int res = -1;
        if( n==1)
            return 0;
        if( n ==0)
            return -1;
        int low = 0 ;
        int high = arr.size() -1;
        int mid ;
        while(low<=high){
            mid = low + (high - low)/2;
            if(arr[mid] == num){
                res = mid ;
                high = mid -1; //向下移动是因为为升序,找到当前num结点 如果要找到最左边的结点则一定要向下移动。
            }
            
            else if(arr[mid]>num){
                high = mid - 1;
            }
            else if (arr[mid]<num){
                low = mid +1;
            }
            
        }
        return res;

    }


有一个有序数组arr,其中不含有重复元素,请找到满足arr[i]==i条件的最左的位置。如果所有位置上的数都不满足条件,返回-1。

给定有序数组arr及它的大小n,请返回所求值。

测试样例:
[-1,0,2,3],4
返回:2

观察到是整形数组,所以元素的增量至少为1,下标差量为1.所以如果arr[0]>n-1 或者arr[n-1]<0存在,则不可能存在arr[i] == i的情况。

假如arr[mid]>mid 那么根据上述条件 high = mid -1 才可能存在 arr[i] ==i

class Find {
public:
    int findPos(vector<int> arr, int n) {
        // write code here
        if(n==0)
            return -1;
        if(arr[0] > n-1 ||arr[n-1]<0){
            return -1;
        }
        int res=-1;
        int low = 0;
        int high = n-1;
        int mid = low + (high - low)/2;
        while(low<=high){   //必须有等于号
            if (arr[low] > low || arr[high] < high) {
                break;
            }
            mid = low + (high - low)/2;
            if(arr[mid]==mid){
                high = mid-1;
                res = mid;
            }
            else if (arr[mid]>mid){
                high = mid - 1;
            }
            else{
                low = mid + 1;
            }
        }
        return res;
    }
};


6.7

给定一棵完全二叉树的根节点root,返回这棵树的节点个数。如果完全二叉树的节点数为N,请实现时间复杂度低于O(N)的解法。


给定树的根结点root,请返回树的大小。


我有些写不来这种递归函数,参考答案如下。

思路大概是先求二叉树的最大层次,然后分左右子树去看层次是否相同,再根据二叉树结点个数和层次的关系去求解。(可能讲的有些模糊)

importjava.util.*;
 
/*
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;
    public TreeNode(int val) {
        this.val = val;
    }
}*/
publicclassCountNodes {
    publicintcount(TreeNode head) {
        if(head == null) {
            return0;
        }
        returnbs(head, 1, mostLeftLevel(head, 1));
    }
 
    publicintbs(TreeNode node, intl, inth) {
        if(l == h) {
            return1;
        }
        if(mostLeftLevel(node.right, l + 1) == h) {
            return(1<< (h - l)) + bs(node.right, l + 1, h);
        else{
            return(1<< (h - l - 1)) + bs(node.left, l + 1, h);
        }
    }
 
    publicintmostLeftLevel(TreeNode node, intlevel) {
        while(node != null) {
            level++;
            node = node.left;
        }
        returnlevel - 1;
    }
}


如果更快的求一个整数k的n次方。如果两个整数相乘并得到结果的时间复杂度为O(1),得到整数k的N次方的过程请实现时间复杂度为O(logN)的方法。

给定kn,请返回k的n次方,为了防止溢出,请返回结果Mod 1000000007的值。

测试样例:
2,3
返回:8

思路:将指数部分转换成二进制,那么二进制对应的每位分别为K^1,K^2,K^3...


class QuickPower {
public:
    int getPower(int k, int N) {
        // write code here
        long result = 1;
        long k_n = k;
        vector<int> binary;
        transTenToTwo(binary,N);
        for(int i = 0 ;i<binary.size();i++){
            
            if(binary[i] == 1){
                result = result *k_n %1000000007;
            }
            k_n =( k_n *k_n)%1000000007;   //防止溢出
        }
        return result;
    }
    
    void transTenToTwo(vector<int> &vec,int num){
        while(num>0){
            vec.push_back(num%2);
            num = num/2;
        }   
    }
};

0 0