剑指offer(1/15)

数字在升序数组中出现的次数

统计一个数字在升序数组中出现的次数。

public class Solution {
    public int GetNumberOfK(int [] array , int k) {
        if(array.length <= 0 || array == null) return 0;
        int first = binarySearch(array,k);
        int last = binarySearch(array,k+1);
        return (first == array.length || array[first] != k) ? 0 : last - first;
    }
    private int binarySearch(int[] nums,int k){
        int low = 0,high = nums.length;
        while(low < high){
            int mid = low + (high - low) / 2;
            if(nums[mid] >= k)//这是大于等于,等于的时候high也等于mid,所以可以找出第一个k的位置和k+1的位置
                high = mid;
            else
                low = low + 1;
        }
        return low;
    }
}
//因为data中都是整数,所以可以稍微变一下,不是搜索k的两个位置,而是搜索k-0.5和k+0.5
//这两个数应该插入的位置,然后相减即可。
class Solution {
public:
    int GetNumberOfK(vector<int> data ,int k) {
        return biSearch(data, k+0.5) - biSearch(data, k-0.5) ;
    }
private:
    int biSearch(const vector<int> & data, double num){
        int s = 0, e = data.size()-1;     
        while(s <= e){
            int mid = (e - s)/2 + s;
            if(data[mid] < num)
                s = mid + 1;
            else if(data[mid] > num)
                e = mid - 1;
        }
        return s;
    }
};

/*
int BinarySearch(vector<int> data, int low, int high, int k)
{
    while (low<=high)
    {
        int m = (high + low) / 2;
        if (data[m] == k)return m;
        else if (data[m] < k) low = m+ 1;
        else high = m - 1;
    }
    return -1;
}
    int GetNumberOfK(vector<int> data ,int k) {
        if(data.size()==0)return 0;
         int len=data.size();
        int KeyIndex=0;
         
        KeyIndex=BinarySearch(data,0,len-1,k);
       if(KeyIndex==-1) return 0;
        int sumber=1;
        int m=KeyIndex-1;
        int n=KeyIndex+1;
       
       while(m>=0&&data[m]==k)
        {
                m--;sumber++;
            }
        while(n<len&&data[n]==k)
        {
               n++; sumber++;
            }
        return sumber;
    }
};
*/

二叉树深度

输入一棵二叉树,求该树的深度。从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度。

/**
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

    public TreeNode(int val) {
        this.val = val;

    }

}
*/
public class Solution {
    public int TreeDepth(TreeNode root) {
        if(root == null) return 0;
        int ld = 1;
        int rd = 1;
        ld = 1 + TreeDepth(root.left);
        rd = 1 + TreeDepth(root.right);
        return ld > rd ? ld : rd;
    }
}
/*
struct TreeNode {
	int val;
	struct TreeNode *left;
	struct TreeNode *right;
	TreeNode(int x) :
			val(x), left(NULL), right(NULL) {
	}
};*/
class Solution {
public:
    int TreeDepth(TreeNode* pRoot){
        if(!pRoot) return 0 ;
        return max(1+TreeDepth(pRoot->left), 1+TreeDepth(pRoot->right));
    }
};

平衡二叉树

输入一棵二叉树,判断该二叉树是否是平衡二叉树。
在这里,我们只需要考虑其平衡性,不需要考虑其是不是排序二叉树
平衡二叉树(Balanced Binary Tree),具有以下性质:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。

public class Solution {
    public boolean IsBalanced_Solution(TreeNode root) {
        if(root == null) return true;
        int left = getDepth(root.left);
        int right = getDepth(root.right);
        int diff = left - right;
        if(diff>1 || diff<-1)
            return false;
        return IsBalanced_Solution(root.left)&&IsBalanced_Solution(root.right);
    }
    private int getDepth(TreeNode root){
        if(root == null) return 0;
        int ld = 1;
        int rd = 1;
        ld = 1 + getDepth(root.left);
        rd = 1 + getDepth(root.right);
        return ld > rd ? ld : rd;
    }
}
class Solution {
public:
    bool IsBalanced_Solution(TreeNode* pRoot) {
        if(pRoot==nullptr)
            return true;
        int left=TreeDepth(pRoot->left);
        int right=TreeDepth(pRoot->right);
        int diff=left-right;
        if(diff>1||diff<-1)
            return false;
        return IsBalanced_Solution(pRoot->left)&&IsBalanced_Solution(pRoot->right);
    }
     
    int TreeDepth(TreeNode* pRoot){
        if(pRoot==nullptr)
            return 0;
        int nL=TreeDepth(pRoot->left);
        int nR=TreeDepth(pRoot->right);
        return (nL>nR)?(nL+1):(nR+1);
    }
};


数组中只出现一次的数字

一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。

// 前提知识:
// 异或运算:如果a、b两个值不相同,则异或结果为1。如果a、b两个值相同,异或结果为0。

// n^0 = n;
// n^n = 0;
// n^n^m = n^(n^m) 满***换律
// 所以,我们可以让数组中的每一个数异或一下,最后会得到一个结果ret,就是两个出现一次的数字的异或结果这个结果肯定是由两个不同数字异或而来,因此我们找ret二进制中为1的位置i,因为1一定是由0,1异或而来,因此要求得两个数中,一定有一个数的二进制中的第i个位置为1, 一个为0.

// 如何找到位置i?可用i = ret ^ (-ret)
// 因为计算机用补码存取二进制数,而负数的补码为反码+1,举个例子
// 假如ret = 1110 , -ret = 0010 , 所以 i = 0010
// 所以,再异或一遍即可得到答案。

//num1,num2分别为长度为1的数组。传出参数
//将num1[0],num2[0]设置为返回结果

public class Solution {
    public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) {
        int num=0;
        for(int i=0;i<array.length;i++){
            num^=array[i];//所有数异或,结果为不同的两个数字的异或
        }
        int count=0;//标志位,记录num中的第一个1出现的位置
        for(;count<array.length;count++){
            if((num&(1<<count))!=0){
                break;
            }
        }
        num1[0]=0;
        num2[0]=0;
        for(int i=0;i<array.length;i++){
            if((array[i]&(1<<count))==0){//标志位为0的为一组,异或后必得到一个数字(这里注意==的优先级高于&,需在前面加())
                num1[0]^=array[i];
            }else{
                num2[0]^=array[i];//标志位为1的为一组
            }
        }   
    }
}
class Solution {
public:
    void FindNumsAppearOnce(vector<int> data,int* num1,int *num2) {
    unordered_map<int, int> map;
    for (int i = 0; i < data.size(); i++)
        map[data[i]]++;
    vector<int>v;
    for (int i = 0; i < data.size(); i++)
        if (map[data[i]]== 1)
            v.push_back(data[i]);
    *num1 = v[0]; *num2 = v[1];
    }
};

和为S的连续正数序列

小明很喜欢数学,有一天他在做数学作业时,要求计算出9~16的和,他马上就写出了正确答案是100。但是他并不满足于此,他在想究竟有多少种连续的正数序列的和为100(至少包括两个数)。没多久,他就得到另一组连续正数和为100的序列:18,19,20,21,22。现在把问题交给你,你能不能也很快的找出所有和为S的连续正数序列? Good Luck!

import java.util.ArrayList;
public class Solution {
    public ArrayList<ArrayList<Integer> > FindContinuousSequence(int sum) {
       ArrayList<ArrayList<Integer> > res = new ArrayList<>();
        int left = 1, right = 2;
        while(left < right){
            int cur = (left + right) * (right - left + 1) / 2;
            if(cur < sum)
                right++;
            if(cur == sum){
                ArrayList<Integer> res1 = new ArrayList<>();
                for(int i = left; i <= right; i++){
                    res1.add(i);
                }
                res.add(res1);
                left++;
            }
            if(cur > sum)
                left++;
        }
        return res;
    }
}
//左神的思路,双指针问题
//当总和小于sum,大指针继续+
//否则小指针+
class Solution {
public:
    vector<vector<int> > FindContinuousSequence(int sum) {
        vector<vector<int> > allRes;
        int phigh = 2,plow = 1;
         
        while(phigh > plow){
            int cur = (phigh + plow) * (phigh - plow + 1) / 2;
            if( cur < sum)
                phigh++;
             
            if( cur == sum){
                vector<int> res;
                for(int i = plow; i<=phigh; i++)
                    res.push_back(i);
                allRes.push_back(res);
                plow++;
            }
             
            if(cur > sum)
                plow++;
        }
         
        return allRes;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值