文章目录
数字在排序数组中出现的次数
题目
统计一个数字在排序数组中出现的次数。
解决方案
- 二分查找
- 分别查找第一次出现和最后一次出现的数字的位置
- 若找到某个数字等于目标数字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对一一的翻转这些单词顺序可不在行,你能帮助他么?
解决方案
- 找空格分割单词
- 分割单词到新数组
- 重新组成新字符串
- 时间复杂度 O ( n ) O(n) O(n)
- 空间复杂度 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;
}
复习内容
- 查找
- string类的使用和类内函数
- C++ 自带平衡二叉树
- vector类函数