论文终于提交了😭,接下来可以好好的学习算法啦,之前看书的时间相对比较少,接下来在博客中打卡。
📆 陪跑秋招。
声明
- 本博文为”恒心“的学习笔记,引用劳烦注明出处。
- 代码参考《剑指Offer》这本书,目前处于初学阶段,读者请慎重阅读。
- 刷题的平台是牛客网。
- 题目的序号按照剑指Offer的顺序进行排序
这里先罗列一下上周的笔记,后期会慢慢。
牛客网真是一个刷题的好地方,强行案例一波。 接下来每天都会将做题笔记更新在博客上。
在练习模式下,可以Debug 对新手太友好了。
正文
3 数组中重复的数字
描述
在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任一一个重复的数字。 例如,如果输入长度为7的数组[2,3,1,0,2,5,3],那么对应的输出是2或者3。存在不合法的输入的话输出-1
示例1
输入:
[2,3,1,0,2,5,3]
返回值:
2
说明:
2或3都是对的
数组中重复的数字
bool duplicate(int numbers[], int length, int* duplication) {
// 防止输入是空指针,或者数组长度为0的情况
if (numbers == nullptr || length <= 0)
{
return false;
}
// 当数组中出现不在范围的数字 直接返回false
for (int i = 0; i < length; i++)
{
if (numbers[i] > length - 1 || numbers[i] < 0)
{
return false;
}
}
// 判断数组中是否有重复的数字,采用小标交换法
for (int i = 0; i < length; i++)
{
//直到当前位置和数组下标值对应下则移动
while (numbers[i] != i )
{
if (numbers[i] == numbers[numbers[i]])
{
// 如果后面出现重复的,则返回重复的数字
*duplication = numbers[i];
return true;
}
// 没有出现重复的,不断进行交换
int temp = numbers[i];
numbers[i] = numbers[temp];
numbers[temp] = temp;
}
}
return false;
}
解题的难点:
-
因为传入的参数比较多,需要做好非法判断
-
判断数组中是否有重复的数字,采用的是下标交换法,这个画图可以解决
牛客网的刷题
https://www.nowcoder.com/practice/6fe361ede7e54db1b84adc81d09d8524
int duplicate(vector<int>& numbers) {
// write code here
if(numbers.size() <1)
return -1;
for(int i=0;i<numbers.size();i++)
{
while(i!=numbers[i])
{
if(numbers[i] == numbers[numbers[i]])
{
return numbers[i];
}
int temp = numbers[i];
numbers[i] = numbers[temp];
numbers[temp] =temp;
}
}
return -1;
}
运行时间:6ms
占用内存:780KB
改进
师兄提供了两个比较妙的解法:
方一 哈希表 开辟空间
bool duplicate(int numbers[], int length, int* duplication) {
vector<bool> result(length,false);
for (int i = 0; i < length; ++i) {
if (result[numbers[i]] == false) {
result[numbers[i]] = true;
}
else
{
duplication[0] = numbers[i];
return true;
}
}
return false;
}
方二 原地做法
bool duplicate(int numbers[], int length, int* duplication) {
for(int i = 0;i < length; ++i){//这个方法妙在对于依次遍历过的每个数,都能在数组里记忆它出现过了。
//比如{2,2,1,0},第一次循环index = 2,a[2]=a[2] + 4 = 5,这样,a[2]=5 > 数组长度4,就说明2这个数字出现过了。
int index = numbers[i]%length;
if( numbers[index] >= length){
duplication[0] = index;
return true;
}
numbers[index] += length;
}
return false;
}
不可以修改Number 数组
注意空间复杂度的解法
解题思路:
利用n个数字 数字范围只有1~n-1这个特性,采用二分法 统计每个区间的数量
范围是数字的范围 与当前数组位置的值无关
int countRange(const int* numbers, int start, int middle, int length)
{
int count = 0;
if (numbers == nullptr || length <= 0)
return count;
for (int i = 0; i < length; i++)
{
if (numbers[i] <= middle && numbers[i] >= start)
++count;
}
return count;
}
int getDuplication(const int* numbers, int length) {
// 空指针以及数组长度为0的情况
if (numbers == nullptr || length <= 0)
return -1;
// 由于n+1长度,所有的数字都在1~n范围,所以根据提题意必然有重复的
// 二分查找法
int start = 1;
int end = length - 1;
while (end >= start)
{
// 位运算 >> 除以2的n次方 注意括号的运算顺序
int middle = ((end - start) >> 1 ) + start;
int count = countRange(numbers,start,middle,length);
if (start == end)
{
if (count > 1)
return start;
else
break;
}
if (count > (middle - start + 1))
end = middle;
else
start = middle + 1;
}
return -1;
}
题4 二维数组中的查找
运行时间:11ms超过29.44% 用C++提交的代码
占用内存:1808KB超过24.52%用C++提交的代码
bool Find(int* matrix, int rows, int columns, int number)
{
// 选择一个可以起到约束的作用的位置,左上角或者右上角
int row = 0;
int colum = columns - 1;
// 判断非法条件:矩阵为空,列和行为空
if (matrix != nullptr && rows > 0 && columns > 0)
{
while (row < rows && colum >=0)
{
// 二维写成一维的形式理解
if (matrix[row * columns + colum] == number) {
return true;
}
else if (matrix[row * columns + colum] < number)
row = row + 1;
else
colum = colum - 1;
}
}
return false;
}
思路
选择一个可以约束的位置,一般这种在左上角和右上角可以找到。
一维指针的二维写法
题5 替换空格
题6 从头到尾打印列表
题7 重建二叉树
8 二叉树的下一个节点
9 用两个栈来实现队列
10 斐波那契额数列
斐波那契
class Solution {
public:
int Fibonacci(int n) {
//因为题目定的是int 不是long long 因此要思考复杂度的问题
int fibResult = 0;
int fib1 = 0;
int fib2 = 1;
if(n == 0)
return 0;
if(n == 1)
return 1;
for(int i=2;i<=n;i++){
fibResult = fib1 + fib2;
fib1 = fib2;
fib2 = fibResult;
}
return fibResult;
}
};
占用内存:528KB超过60.20%用C++提交的代码
运行时间:3ms超过39.46% 用C++提交的代码
青蛙跳台阶
运行时间:313ms超过29.58% 用C++提交的代码
占用内存:528KB超过65.44%用C++提交的代码
class Solution {
public:
int jumpFloor(int number) {
// 求一共有多少种跳法
// 要么跳一级剩下j(n-1),要么两级剩下j(n-1)
// 直到需要跳的阶数为0
int jumpNum = 0;
if(number<0)
return 0;
if(number==0)
return 1;
jumpNum = jumpFloor(number-1) + jumpFloor(number-2);
return jumpNum;
}
};
面试题11 旋转数组最小的数字
描述
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。
输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。
NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。
示例1
输入:
[3,4,5,1,2]
复制
返回值:
1
一开始做的时候,还是做错了
运行时间:7ms超过94.97% 用C++提交的代码
占用内存:880KB超过33.20%用C++提交的代码
[5,1,2,5,5,5,5,5,5]
犯错…
if(rotateArray[startIndex] == rotateArray[endIndex]
== rotateArray[midIndex])
class Solution {
public:
int minNumberInRotateArray(vector<int> rotateArray) {
if(rotateArray.size()==0)
return 0;
// 用两个标记位置标记开始和结束
// 一般情况下 利用二分查找法,当两个位置的中间值大于起始位置移动开始位置到中间
// 反之右边移动
// 如果差值为1,这输出后面的位置
// 考虑到一种情况 就是第一个位置的问题 indexMid = index
int startIndex = 0;
int endIndex = rotateArray.size()-1;
// 如果第一个就是我们需要查找的则直接返回
int midIndex = startIndex;
// rotateArray[startIndex] >= rotateArray[endIndex] 确保旋转
while(rotateArray[startIndex] >= rotateArray[endIndex]){
midIndex = int((startIndex + endIndex) / 2);
// 针对特殊的例子,采用特殊的解法
if(rotateArray[startIndex] == rotateArray[endIndex]
&& rotateArray[startIndex] == rotateArray[midIndex])
return minNumberR(rotateArray,startIndex,endIndex);
if(rotateArray[midIndex] >=rotateArray[startIndex])
startIndex = midIndex;
else if(rotateArray[midIndex]<= rotateArray[endIndex])
endIndex = midIndex;
if(endIndex - startIndex == 1){
midIndex = endIndex;
return rotateArray[midIndex];
}
}
return rotateArray[midIndex];
}
int minNumberR(vector<int> &rotateArray, int left, int right){
int result = rotateArray[left];
for(int i = left + 1; i < right;++i)
if(rotateArray[i]<result){
result = rotateArray[i];
}
return result;
}
};
矩阵中的路径
描述
请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一个格子开始,每一步可以在矩阵中向左,向右,向上,向下移动一个格子。如果一条路径经过了矩阵中的某一个格子,则该路径不能再进入该格子。 例如
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ys2uEvv9-1629620736843)(image/README/image/image-20210815193700324.png)]
矩阵中包含一条字符串"bcced"的路径,但是矩阵中不包含"abcb"路径,因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入该格子。
示例1
输入:
[[a,b,c,e],[s,f,c,s],[a,d,e,e]],"abcced"
返回值:
true
示例2
输入:
[[a,b,c,e],[s,f,c,s],[a,d,e,e]],"abcb"
返回值:
false
备注:
0 <= matrix.length <= 200
0 <= matrix[i].length <= 200
始终过不了这个例子
[[A,B,C,E,H,J,I,G],[S,F,C,S,L,O,P,Q],[A,D,E,E,M,N,O,E],[A,D,I,D,E,J,F,M],[V,C,E,I,F,G,G,S]],“SGGFIECVAASABCEHJIGQEM”
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param matrix char字符型vector<vector<>>
* @param word string字符串
* @return bool布尔型
*/
bool hasPath(vector<vector<char> >& matrix, string word) {
// 临界条件的判断
if(matrix.empty() || matrix[0].empty() || word.length()<=0){
return false;
}
// 获取行号用于遍历
int rows = matrix.size();
int cols = matrix[0].size();
int pathLength = 0;
// 标记位置
bool *visited = new bool[rows * cols];
// 这里必须要要对访问的数组初始化 否则调试结结果和运行结果不一致
memset(visited,0,rows*cols);
// 对于每一个位置进行是否为路径的判断
for(int row = 0; row<rows; ++row){
for(int col = 0; col<cols; ++col){
// 如果最终在矩阵中找到
if(hasCorePath(matrix,rows,cols,row,col,pathLength,word,visited)){
return true;
}
}
}
delete[] visited;
return false;
}
bool hasCorePath(vector<vector<char> >& matrix,
int rows, int cols, int row, int col,
int &length,const string &word, bool *visit){
if(word[length] == '\0'){
return true;
}
bool comRound = false;
// 如果行数和列数符合要求同时当前位置与当前目标的值相等,长度--
// 且没有被访问过的
if(col>=0 && row>=0
&& col<cols && row<rows
&& !visit[row*cols + col]
&& matrix[row][col] == word[length]){
length++;
// 判断完后 设置已访问
visit[row*cols + col] =true;
// 左上右下
comRound = hasCorePath(matrix,rows,cols,row,col-1,length,word,visit)
|| hasCorePath(matrix,rows,cols,row-1,col,length,word,visit)
|| hasCorePath(matrix,rows,cols,row,col+1,length,word,visit)
|| hasCorePath(matrix,rows,cols,row+1,col,length,word,visit);
// 回溯
if(!comRound){
visit[row*cols + col] =false;
length--;
}
}
return comRound;
}
};
运行时间5ms
占用内存648KB
这里有一个巨坑!!!
漏了初始化,memset()
// 这里必须要要对访问的数组初始化 否则调试结结果和运行结果不一致
memset(visited,0,rows*cols);
class Solution {
public:
bool hasPath(vector<vector<char> >& board, string word) {
const int m = board.size(), n = board[0].size();
for (int y = 0; y < m; ++y)
for (int x = 0; x < n; ++x)
if (search(board, m, n, x, y, 0, word))
return true;
return false;
}
private:
bool search(vector<vector<char>>& board, int m, int n, int x, int y, int p, const string& word) {
if (x < 0 || x == n || y < 0 || y == m || board[y][x] != word[p])
return false;
if (p == word.length() - 1)
return true;
const char t = board[y][x];
board[y][x] = 0;
bool found = search(board, m, n, x - 1, y, p + 1, word) ||
search(board, m, n, x + 1, y, p + 1, word) ||
search(board, m, n, x, y - 1, p + 1, word) ||
search(board, m, n, x, y + 1, p + 1, word);
board[y][x] = t;
return found;
}
};
面试题13 机器人的运动范围
运行时间:4ms超过11.19% 用C++提交的代码
占用内存:676KB超过9.99%用C++提交的代码
利用书上的方法去做
但是效率太低下了
class Solution {
public:
int movingCount(int threshold, int rows, int cols) {
// 这道题和矩阵中路径类似,不同的是只需要遍历一次就可以了
if(threshold < 0 || rows<=0 || cols<=0)
return 0;
// 设置一个访问的数组,当前的每一个位置开始遍历
bool *visited = new bool[rows * cols];
memset(visited,0,rows*cols);
// 统计有效的移动范围
int count = movingCountCore(threshold, rows,cols,0,0,visited);
delete []visited;
return count;
}
//先判断当前位置能否进入相邻 然后在判断
int movingCountCore(int threshold,int rows, int cols, int row, int col, bool *visted)
{
int count =0;
if(check(threshold, rows, cols, row, col,visted))
{
visted[row*cols + col] =true;
// 左上右下
count = 1 + movingCountCore(threshold, rows, cols,
row-1,col, visted)
+ movingCountCore(threshold, rows, cols,
row, col-1, visted)
+ movingCountCore(threshold, rows, cols,
row+1, col, visted)
+ movingCountCore(threshold, rows, cols,
row, col+1, visted);
}
return count;
}
bool check(int threshold,int rows, int cols, int row, int col, bool *visted)
{
if(row>=0 && row<rows && col>=0 && col< cols
&& getDigitSum(row)+getDigitSum(col)<=threshold
&&!visted[row*cols +col])
return true;
return false;
}
int getDigitSum(int num)
{
int sum = 0;
while(num>0)
{
sum += num%10;
num /=10;
}
return sum;
}
};
面试题14 剪绳子
动态规划做出来
但是效率并不高
运行时间:4ms超过21.99% 用C++提交的代码
占用内存:568KB超过32.41%用C++提交的代码
class Solution {
public:
int cutRope(int number) {
int product[number+1];
// 写几个例子后发现 有递归的规律
// 先把特殊绳子直接返回
if(number == 2)
return 1;
if(number == 3)
return 2;
if(number == 4)
return 4;
// 大于4之后的 可以通过保存最优解决来解决
product[0] = 0;
product[1] = 1;
product[2] = 2;
product[3] = 3;
int max = product[3];
for(int i=4; i<=number; i++)
{
max = 0;
// 由于我们需要改变的第4个之后的,所以还需要加一个循环
for(int j=0;j<=i/2; j++){
product[i] = product[j]*product[i-j];
if(product[i] >max)
{
max = product[i];
}
}
// 当前当前状态最优解
product[i] = max;
}
return max;
}
};
贪心算法求解
运行时间:4ms超过21.99% 用C++提交的代码
占用内存:592KB超过29.38%用C++提交的代码
class Solution {
public:
int cutRope(int number) {
// 找规律用贪心算法,原理就是 尽可能的多剪成3份
if(number==2)
return 1;
if(number==3)
return 2;
if(number==4)
return 4;
// 尽可能剪成3份
int timesOf3 = number/3;
// 如果剩下的是4的情况就不该剪成3而是2;此时长度-3 =1
int timesOf2 = 0;
if(number - timesOf3*3 == 1)
{
timesOf3--;
}
timesOf2 = (number - timesOf3*3)/2;
return pow(3,timesOf3) * pow(2,timesOf2);
}
};
面试题15 二进制中的1的个数
注意
防止负数number
运行时间:4ms超过7.70% 用C++提交的代码
占用内存:608KB超过18.76%用C++提交的代码
class Solution {
public:
int NumberOf1(int n) {
int length = 0;
unsigned int flag = 1;
// 循环结束的终止条件是32位整数的第32位
while(flag)
{
if(n & flag)
length++;
flag = flag<<1;
}
return length;
}
};
小结:
把一个整数减去1后,再和原来整数做与运算,会把该整数最右边的1变成0
比如 5
1101
(1101-1) & 1101 = 1100
(1100-1) & 1100 = 1000
(1000-1) & 1000 = 0
class Solution {
public:
int NumberOf1(int n) {
//比如 5 1101
//(1101-1) & 1101 = 1100
//(1100-1) & 1100 = 1000
//(1000-1) & 1000 = 0
int count = 0;
while(n)
{
count++;
n = (n-1)&n;
}
return count;
}
};
面试题16 数值的整数次方
运行时间:5ms超过3.86% 用C++提交的代码
占用内存:572KB超过22.73%用C++提交的代码
基于规则
class Solution {
public:
double Power(double base, int exponent) {
int exponentAbs = exponent;
// 任何非0的次方
if(exponent==0)
return 1.00;
// 关于底数为负数的正次方的问题
else if((base<=0.0 && exponent>0) || (base>=0.0 && exponent>0))
{
if(exponent <0)
exponentAbs =-exponent;
return PowerWithEx(base,exponentAbs);
}
// 当底数为负数 指数为负数的时候 倒数的平方
else if(base<0.0 && exponent<0)
{
exponentAbs =-exponent;
return 1.0/PowerWithEx(base,exponent);
}
// 当底数为正数,指数为负数
else
{
exponentAbs =-exponent;
return 1.0/PowerWithEx(base,exponentAbs);
}
}
double PowerWithEx(double base, int exponent)
{
double result = base;
for(int i=1; i<exponent; ++i)
{
result *= base;
}
return result;
}
};
与斐波那契数列一样,这部分依然有值得优化的地方
运行时间:3ms超过33.19% 用C++提交的代码
占用内存:592KB超过21.59%用C++提交的代码
class Solution {
public:
double Power(double base, int exponent) {
int exponentAbs = exponent;
// 任何非0的次方
if(exponent==0)
return 1.00;
// 关于底数为负数的正次方的问题
else if((base<=0.0 && exponent>0) || (base>=0.0 && exponent>0))
{
if(exponent <0)
exponentAbs =-exponent;
return PowerWithEx(base,exponentAbs);
}
// 当底数为负数 指数为负数的时候 倒数的平方
else if(base<0.0 && exponent<0)
{
exponentAbs =-exponent;
return 1.0/PowerWithEx(base,exponent);
}
// 当底数为正数,指数为负数
else
{
exponentAbs =-exponent;
return 1.0/PowerWithEx(base,exponentAbs);
}
}
double PowerWithEx(double base, int exp)
{
// 采用Fib的优化方法的时候,需要注意exp=0.exp=1的情况
if(exp==0)
return 1;
if(exp==1)
return base;
double result = PowerWithEx(base, exp>>1);
result *= result;
if(exp & 0x1 ==1)
return result *= base;
return result;
}
};
面试题17 大数问题 从1到最大的N位数
大数问题
牛客网好像没有找到这一题的解法。
面试题18 删除链表的节点
删除重复的链表的节点
面试题19 正则表达式匹配
运行时间:3ms超过85.25% 用C++提交的代码
占用内存:432KB超过84.79%用C++提交的代码
描述
请实现一个函数用来匹配包括’.‘和’‘的正则表达式。模式中的字符’.‘表示任意一个字符,而’'表示它前面的字符可以出现任意次(包含0次)。 在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串"aaa"与模式"a.a"和"abaca"匹配,但是与"aa.a"和"ab*a"均不匹配
示例1
输入:
"aaa","a*a"
返回值:
true
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param str string字符串
* @param pattern string字符串
* @return bool布尔型
*/
bool match(string str, string pattern) {
// write code here
//
// 边界判断
if(str.length()<0 || pattern.length()<0)
return false;
return matchCore(str,pattern,0,0);
}
bool matchCore(string str, string pattern,int i,int j){
//如果两个字符串都到达了末尾 trues
if(str[i]=='\0' && pattern[j]=='\0')
return true;
// 如果只有其中一个到达末尾则 false 这是不对的
// 错误 写法|| (str[i]!='\0' && pattern[j]=='\0')
if((str[i]!='\0' && pattern[j]=='\0'))
{
return false;
}
// 如果当前位置的下一个是* 则分为3种情况
if(pattern[j+1]=='*')
{
// 一种是当前位置和需要匹配的相等则
if(str[i]==pattern[j] || (pattern[j]=='.'&&str[i]!='\0'))
{
// 一种是str移动两个位置,模式+1
// 一种算是str移动一个 模式保持不变
return matchCore(str,pattern,i+1,j+2) ||
matchCore(str, pattern, i+1, j) ||
matchCore(str, pattern, i, j+2);
}
// 一种是直接忽略* 以及其前面的
else
{
return matchCore(str, pattern, i, j+2);
}
}
// 匹配才移动 直接判断是否匹配,然后一定各+1
if(str[i]==pattern[j] ||(pattern[j]=='.' && str[i]!='\0'))
{
return matchCore(str, pattern, i+1, j+1);
}
return false;
}
};
20 表示数值的字符串
描述
请实现一个函数用来判断字符串str是否表示数值(包括科学计数法的数字,小数和整数)。
科学计数法的数字(按顺序)可以分成以下几个部分:
1.若干空格
2.一个整数或者小数
3.(可选)一个 ‘e’ 或 ‘E’ ,后面跟着一个整数(可正可负)
4.若干空格
小数(按顺序)可以分成以下几个部分:
1.若干空格
2.(可选)一个符号字符(’+’ 或 ‘-’)
\3. 可能是以下描述格式之一:
3.1 至少一位数字,后面跟着一个点 ‘.’
3.2 至少一位数字,后面跟着一个点 ‘.’ ,后面再跟着至少一位数字
3.3 一个点 ‘.’ ,后面跟着至少一位数字
4.若干空格
整数(按顺序)可以分成以下几个部分:
1.若干空格
2.(可选)一个符号字符(’+’ 或 ‘-’)
\3. 至少一位数字
4.若干空格
例如,字符串["+100",“5e2”,"-123",“3.1416”,"-1E-16"]都表示数值。
但是[“12e”,“1a3.14”,“1.2.3”,“±5”,“12e+4.3”]都不是数值。
提示:
1.1 <= str.length <= 20
2.str 仅含英文字母(大写和小写),数字(0-9),加号 ‘+’ ,减号 ‘-’ ,空格 ’ ’ 或者点 ‘.’ 。
3.如果怀疑用例是不是能表示为数值的,可以使用python的print(float(str))去查看
示例1
输入:
"123.45e+6"
返回值:
true
运行时间:3ms超过87.76% 用C++提交的代码
占用内存:508KB超过22.89%用C++提交的代码
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param str string字符串
* @return bool布尔型
*/
// 数字的格式可以用A[.[B]][e|EC]或者.B[e|EC] 表示
// 其中A,C 都是整数(可以有正负号) 而B是一个无符号整数
bool isNumeric(string str) {
// write code here
if(str.length()<0 || str.empty())
return false;
bool flag = hasNumber(str,0);
if(!flag)
return false;
// 定义一个下标判断正负号部分
int i=0;
// 对于一个数字都没有的字符串直接返回
bool numeric = scanInteger(str,i);
// 如果出现'.' 则接下来是数字的小数部分
if(str[i]=='.')
{
++i;
// 下面一行代码用||的原因:
//1. 小数可以没有整数部分,如.123等于0.123
//2. 小数点后面可以诶呦数字,如2333. 等于 2333.0
//3。 小数点前面和后面可以都有数字 如 233.66
numeric = scanUnsignedInter(str,i) || numeric;
}
// 如果出现'e' 或则‘E’, 则接下来时数字的指数部分
if(str[i] == 'e' || str[i] == 'E')
{
++i;
// 下面一行代码用&&的原因
// 1. 当e或E前面没有数字的时候,整个字符串不能表示数字,如.e1
// 2. 当e或E后面没有整数时,整个字符串不能表示数字,如12e,12e+5.4
numeric = numeric && scanInteger(str,i);
}
return numeric && str[i]=='\0';
}
// 特殊案例检测
bool hasNumber(string str, int j)
{
while(str[j])
{
if(str[j]>='0' && str[j]<='9')
return true;
j++;
}
return false;
}
// 扫描可能以+-开始的起始数位 A,C
bool scanInteger(string str, int &i)
{
while(str[i]==' ' && str[i]!='\0')
i++;
if(str[i]=='+' || str[i]=='-')
++i;
return scanUnsignedInter(str,i);
}
//扫描字符串中0-9的 数位 A B C
bool scanUnsignedInter(string str, int &i)
{
const int berforeI = i;
//题目要求可以有若干个空格
while((str[i]!='\0' && str[i]>='0' && str[i]<='9')
|| str[i]==' ')
++i;
// 当str中存在0-9 则下标会变大,返回true;
return i>berforeI;
}
};
栈与队列
栈和队列的一些基本语法
栈
std::stack<int> S;
S.empty()
S.push(10)
S.pop()
S.top()
队列
std::queue<int> Q;
Q.push(5)
Q.pop()
Q.top()
9 用两个栈实现队列
方法做起来很简单,但是题目居然出奇的没看懂。。。
class CQueue {
public:
std::stack<int> s;
std::stack<int> temp_s;
CQueue() {
}
void appendTail(int value) {
s.push(value);
}
int deleteHead() {
if(s.empty())
return -1;
while(s.size()!=1){
temp_s.push(s.top());
s.pop();
}
int value = s.top();
s.pop();
while(!temp_s.empty()){
// 这部分要把临时栈的数据还给原来的栈
s.push(temp_s.top());
temp_s.pop();
}
return value;
}
};
/**
* Your CQueue object will be instantiated and called as such:
* CQueue* obj = new CQueue();
* obj->appendTail(value);
* int param_2 = obj->deleteHead();
*/
30 包含min函数的栈
class MinStack {
public:
/** initialize your data structure here. */
std::stack<int> stack;
std::stack<int> min_stack;
MinStack() {
min_stack.push(INT_MAX);
}
void push(int x) {
stack.push(x);
if(x>min_stack.top()){
x=min_stack.top();
}
min_stack.push(x);
}
void pop() {
stack.pop();
min_stack.pop();
}
int top() {
return stack.top();
}
int min() {
return min_stack.top();
}
};
21 调整数组顺序
书本上的做法
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param array int整型vector
* @return int整型vector
*/
vector<int> reOrderArray(vector<int>& array) {
// write code here
// 通过两个位置,开始和结尾
int startI = 0;
int endI = array.size()-1;
while(startI < endI)
{
// 第一个位置向后移动,直到为偶数的时候停下来
while(startI < endI && (array[startI] & 0x1)!=0)
startI++;
// 遇到奇数停下来
while(startI < endI && (array[endI] & 0x1)==0)
endI--;
if(startI<endI)
{
int temp = array[startI];
array[startI] = array[endI];
array[endI] = temp;
}
}
return array;
}
};
描述
输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。
示例1
输入:
[1,2,3,4]
返回值:
[1,3,2,4]
运行时间:11ms超过54.01% 用C++提交的代码
占用内存:1644KB超过28.57%用C++提交的代码
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param array int整型vector
* @return int整型vector
*/
vector<int> reOrderArray(vector<int>& array) {
// write code here
// 定义一个新的容器,偶数的放在前面 奇数的放在后面
vector<int> sortArray = {};
// 奇数在前
for(int i=0; i<array.size(); ++i)
{
if(array[i] %2 != 0)
sortArray.push_back(array[i]);
}
// 偶数在后
for(int i=0; i<array.size(); ++i)
{
if(array[i] % 2 ==0)
sortArray.push_back(array[i]);
}
return sortArray;
}
};
改进但也没提升多少啊
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param array int整型vector
* @return int整型vector
*/
vector<int> reOrderArray(vector<int>& array) {
// write code here
// 定义一个新的容器,偶数的放在前面 奇数的放在后面
vector<int> endArray(array.size(), 0);
// 将前后两部分一次性存下来,但是注意处理作用域
int frontIndex = 0;
int endIndex = 0;
for(auto a : array)
{
if((a & 1)==1)
array[frontIndex++] = a;
else
endArray[endIndex++] = a;
}
// 偶数在后
for(int i=0; i<endIndex; ++i)
{
array[frontIndex++] = endArray[i];
}
return array;
}
};
超过45.41% 用C++提交的代码
占用内存:1800KB超过7.19%用C++提交的代码
博主分享了算法学习的进度,提交论文后专注于算法,包括数组中重复数字、二分查找、矩阵路径、字符串处理、动态规划等问题的解法,并记录了牛客网刷题的体验。此外,还讨论了栈与队列、链表操作、二进制数的处理等数据结构问题。
1472

被折叠的 条评论
为什么被折叠?



