【剑指offer】知识迁移

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

题目

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

解决方案

  • 二分查找
  • 分别查找第一次出现和最后一次出现的数字的位置
  • 若找到某个数字等于目标数字k,如果该数字对应序号为0,则为第一次出现;若对应数字序号不为0,检查这个数字前的数字,若相同,继续对前半部分用二分法;反之则为第一次出现的数字
  • 找最后一个数字原理同上

代码

	int GetNumberFirst(vector<int>& data, int k, int start, int end) {
        if (start > end)
            return -1;

        int midindex = (start + end) / 2;
        if (data[midindex] == k) {
            if ((midindex > 0 && data[midindex - 1] != k) || midindex == 0)
                return midindex;
            else
            {
                end = midindex - 1;
            }
        }
        else if (data[midindex] > k) {
            end = midindex - 1;
        }
        else
        {
            start = midindex + 1;
        }
        return GetNumberFirst(data, k, start, end);
    }

    int GetNumberLast(vector<int>& data, int k, int start, int end) {
        if (start > end)
            return -1;

        int midindex = (start + end) / 2;
        int len = data.size() - 1;
        if (data[midindex] == k) {
            if ((midindex < len && data[midindex + 1] != k) || midindex == len)
                return midindex;
            else
            {
                start = midindex + 1;
            }
        }
        else if (data[midindex] > k) {
            end = midindex - 1;
        }
        else
        {
            start = midindex + 1;
        }
        return GetNumberLast(data, k, start, end);
    }
    int GetNumberOfK(vector<int> data ,int k) {
        if (data.size() == 0)
            return 0;
        int start = 0;
        int end = data.size() - 1;
        int indexfirst = GetNumberFirst(data, k, start, end);
        int indexlast = GetNumberLast(data, k, start, end);

        if (indexfirst == -1 || indexlast == -1)
            return 0;
        else
            return indexlast - indexfirst + 1;
    }

二叉树的深度

题目

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

解决方案

  • 如果是叶节点,深度为0
  • 如果有左子树,深度加1
  • 如果有右子树,深度加1
  • 如果同时有左右子树,取深度最大的那个加1
  • 递归实现
  • 时间复杂度 O ( n ) O(n) O(n)
  • 空间复杂度 O ( n ) O(n) O(n)

代码

#include<iostream>
#include<algorithm>
#include<vector>
#include<string>

using namespace std;

//================================功能代码===========================================
struct TreeNode {
	int val;
	struct TreeNode *left;
	struct TreeNode *right;
	TreeNode(int x) :
		val(x), left(NULL), right(NULL) {
	}
};

int TreeDepth(TreeNode* pRoot) {
	if (pRoot == nullptr) {
		return 0;
	}

	int LeftDepth = TreeDepth(pRoot->left);
	int RightDepth = TreeDepth(pRoot->right);

	return (LeftDepth > RightDepth) ? LeftDepth : RightDepth + 1;
}

判断平衡二叉树

题目

输入一棵二叉树,判断该二叉树是否是平衡二叉树。

在这里,我们只需要考虑其平衡性,不需要考虑其是不是排序二叉树

解决方案

  • 后序遍历
  • 先判断左右子树是否为平衡二叉树,再判断根节点
  • 需要记录树的深度
  • 时间复杂度 O ( n ) O(n) O(n)
  • 空间复杂度 O ( n ) O(n) O(n)

代码

bool isBlanced(const BinaryTreeNode* pRoot, int& depth) {
	if (pRoot == nullptr) {
		depth = 0;
		return true;
	}

	int left, right;
	if (isBlanced(pRoot->m_pLeft, left) && isBlanced(pRoot->m_pRight, right))
	{
		int diff = left - right;
		if (diff <= 1 && diff >= -1) {
			depth = (left > right) ? (left + 1) : (right + 1);
			return true;
		}
	}

	return false;
}

bool isBalanced(const BinaryTreeNode* pRoot) {
	int depth;
	return isBlanced(pRoot,depth);
}

数组中只出现一次的数字

题目

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

解决方案

  • 如果找一个唯一存在的数字,直接对所有数字求异或,留下来的数字便是
  • 将所有数字分为两个组,每个组包含一个出现一次的数字
  • 先将所有数字求异或,取得到数字二进制中从右开始第一个数字1,假设为第 n n n位置
  • 所有数字,第 n n n位置为1的分一组,为0的分一组
  • 分组求异或,得到两个之出现一次的值

代码

 void FindNumsAppearOnce(vector<int> data,int* num1,int *num2) {
        int length = data.size();
        if (length <= 2)
            return;

        int resultExclusiveOR = 0;
        for (int i = 0; i < length; i++)
        {
            resultExclusiveOR ^= data[i];
        }

        //找最右第一个是1的位置
        unsigned int indexOf1 = FindFirstBitIs1(resultExclusiveOR);

        //按照那个位置是不是1对数组分类
        *num1 = *num2 = 0;
        for (int j = 0; j < length; j++)
        {
            if (IsBit1(data[j], indexOf1))
                *num1 ^= data[j];
            else
                *num2 ^= data[j];
        }
    }
    
    unsigned int FindFirstBitIs1(int num)
    {
        int indexBit = 0;
        while (((num&1)==0) && (indexBit<8*sizeof(int)))
        {
            num = num >> 1;
            ++indexBit;
        }

        return indexBit;
    }
    
    bool IsBit1(int num, unsigned int indexBit)
    {
        num = num >> indexBit;
        return(num & 1);
    }

和为S的连续正数序列

题目

输出所有和为S的连续正数序列。序列内按照从小至大的顺序,序列间按照开始数字从小到大的顺序

解决方案

  • 用small和big两个数表示序列的开始和结尾
  • 若序列和小于目标值,则序列后移一位,增加一个数字
  • 若序列和大于目标值,则序列最小值后裔一位,去掉第一个数字
  • 序列至少有两个数字,终止条件为small值小于(1+sum)/2
  • 4不存在这样的序列,目标值至少等于3
  • 时间复杂度 O ( n u m ) O(num) O(num)
  • 空间复杂度 O ( 1 ) O(1) O(1)

代码

vector<vector<int> > FindContinuousSequence(int sum) {
        vector<vector<int> > res;
        if (sum < 3)
            return res;

        int small = 1;
        int big = 2;
        int cursum = small + big;
        int middle = (1 + sum) / 2;

        while (small < middle) {
            if (sum == cursum)
            {
                vector<int> temp;
                for (int i = small; i <= big; i++)
                {
                    temp.push_back(i);
                }
                res.push_back(temp);
                big += 1;
			    cursum += big;
            }
            else if (sum < cursum)
            {
                cursum -= small;
                small += 1;
            }
            else 
            {
                big += 1;
                cursum += big;
            }
        }

        return res;
    }

翻转单词顺序列

题目

牛客最近来了一个新员工Fish,每天早晨总是会拿着一本英文杂志,写些句子在本子上。同事Cat对Fish写的内容颇感兴趣,有一天他向Fish借来翻看,但却读不懂它的意思。例如,“student. a am I”。后来才意识到,这家伙原来把句子单词的顺序翻转了,正确的句子应该是“I am a student.”。Cat对一一的翻转这些单词顺序可不在行,你能帮助他么?

解决方案

  1. 找空格分割单词
  2. 分割单词到新数组
  3. 重新组成新字符串
  4. 时间复杂度 O ( n ) O(n) O(n)
  5. 空间复杂度 O ( n ) O(n) O(n)

代码

string ReverseSentence(string str) {
        string res;
        if(str.size() == 0)
            return res;
        
        vector<string> sub_str;
        int begin=0;
        int end=str.find(" ",0);
        while(end != string::npos){
            string temp = str.substr(begin, end - begin);
            sub_str.push_back(temp);
            begin = ++end;
            end = str.find(" ", begin);
        }
        sub_str.push_back(str.substr(begin, str.size() - begin));
        
        for(int i=sub_str.size()-1;i>=0;i--){
            res = res + sub_str[i];
            res += " ";
        }
        
        res.erase(res.size()-1, 1);
        
        return res;
    }

复习内容

  1. 查找
  2. string类的使用和类内函数
  3. C++ 自带平衡二叉树
  4. vector类函数
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值