50+100+针对训练。
感谢大佬几款优秀的支持C、C++在线编译器
此外,教程网站:九章算法课-免费试听可以闲的时候过渡一下,换换思路听着。
另,十大排序算法需要整理一下,参考:1.0 十大经典排序算法
其实主要要整理数据结构与算法
stage2——4天进阶阶段
在线编译器:compile c++ gcc online
刷题网站:阶段1第一关:基本数据类型
day2-3 planA
lintcode 余4-6
教程完成度100%。
Q&A
1.两字符串和
接着昨天的继续。
字符转数字:char c; int i=c-'0';
,注意,减去的是字符'0'
,不是数字。
数字转字符:int i; char c=i+'0';
,注意,加上的还是字符'0'
,不是数字。
此外,数字转字符其实用的是to_string
,因为可能出现加和为两位数的情况。
class Solution {
public:
/**
* @param A: a string
* @param B: a string
* @return: return the sum of two strings
*/
string SumofTwoStrings(string &A, string &B) {
// write your code here
#if 1 //第1种
int size=A.size()>B.size()?A.size():B.size();
int sum;//每一位和
string S;//保存结果
int a=stoi(A),b=stoi(B);
for(int i=0;i<size;i++)
{
sum=a%10+b%10;
S=to_string(sum)+S;
a/=10;
b/=10;
}
return S;
#endif
}
};
昨天说到stoi
函数有检测范围的问题。
当字符串中有除了数字外的字符时,只会将这些字符前的数字转换为int
。
此外还有atoi
函数,stoi
的参数是const string*
,atoi
的参数是const char*
因此改进下:
class Solution {
public:
/**
* @param A: a string
* @param B: a string
* @return: return the sum of two strings
*/
string SumofTwoStrings(string &A, string &B) {
// write your code here
//原思路,取每位转数字求和再转字符
int size=A.size()<B.size()?A.size():B.size();
int sum;
string S="";
string rest;
for(int i=0;i<size;i++)
{
sum=(A[A.size()-1-i]-'0')+(B[B.size()-1-i]-'0');
S=to_string(sum)+S;
}
if(A.size()>size) rest.assign(A,0,A.size()-size);
else if(B.size()>size) rest.assign(B,0,B.size()-size);
S=rest+S;
return S;
}
};
今天再强调另一个要点:
s.assign(str,index);
默认只有字符串和数字两个参数的时候,是将str
从index
起的所有元素赋值给s
,而不是将前index
个字符进行赋值。如果要给定区间,使用s.assign(str,index,num)
。
2.首字母大写
类似【翻转字符串问题】,参见[学习笔记-C++篇]day11 lintcode50
class Solution {
public:
/**
* @param s: a string
* @return: a string after capitalizes the first letter
*/
string capitalizesFirst(string &s) {
// Write your code here
string str;
bool judge=true;
for(int i=0;i<s.size();i++)
{
if(s[i]!=' ' && judge==true)
{
if(islower(s[i])) str.push_back(s[i]-32);
judge=false;
continue;
}
else if(s[i]==' ') judge=true;
str.push_back(s[i]);
}
return str;
}
};
3.回文数
类似【回文数2】,参见[学习笔记-C++篇]day11 lintcode50。
但是当时只熟悉到vector
,所以遍历取数字每一位保存到数组中,然后翻转数组。
现在可以直接用int
转string
,实现翻转。
class Solution {
public:
/**
* @param num: a positive number
* @return: true if it's a palindrome or false
*/
bool isPalindrome(int num) {
// write your code here
string s,rs;
s=to_string(num);
rs=s;
reverse(rs.begin(),rs.end());
if(s==rs) return true;
else return false;
}
};
4.最长单词
暴力环。
class Solution {
public:
/*
* @param dictionary: an array of strings
* @return: an arraylist of strings
*/
vector<string> longestWords(vector<string> &dictionary) {
// write your code here
//遍历1次,那么一旦出现大于现有值的时候就需要清空数组
vector<string> sout;
sout.push_back(dictionary[0]);
int tmp;//保存字符串临时长度
tmp=dictionary[0].size();
for(int i=1;i<dictionary.size();i++)
{
if(dictionary[i].size()==tmp) sout.push_back(dictionary[i]);
else if(dictionary[i].size()>tmp)
{
sout.clear();
sout.push_back(dictionary[i]);
tmp=dictionary[i].size();
}
}
return sout;
}
};
会超时。不管了,别的题解也有这样的思路,但是不会超时?离谱。
class Solution {
public:
/*
* @param dictionary: an array of strings
* @return: an arraylist of strings
*/
vector<string> longestWords(vector<string> &dictionary) {
// write your code here
int tmp=0;
for(int i=0;i<dictionary.size();i++)
{
tmp=tmp>=dictionary[i].size()?tmp:dictionary[i].size();
}
vector<string> sout;
for(int j=0;j<dictionary.size();j++)
{
if(dictionary[j].size()==tmp) sout.push_back(dictionary[j]);
}
return sout;
}
};
还是会卡,反正暴力就是会卡时间。
5.最后一个单词的长度
仍旧和第2题类似。
注意点:1)字符串是否为空;2)最后一个单词是否含有空格。
就如何删除string
中空格的指令,我给出了2个答案,但是奇怪的是,用#if 0
注释掉的部分在编译器中是可以正确运行的,但是核心代码无法正确识别。
参考C++从string中删除所有的某个特定字符。
法1:str.erase(index,num);
删除字符串str
中从索引index
开始的num
个元素。
法2:str.erase(remove(str.begin(),str.end(),c),str.end());
先用remove
删除字符串str
中等于字符c
的元素,得到一个新的字符串,但remove
的返回值是一个迭代器(指向新容器的end
),然后结合erase
删除从迭代器开始到end
的元素,就是新的str
。
class Solution {
public:
/**
* @param s: A string
* @return: the length of last word
*/
int lengthOfLastWord(string &s) {
// write your code here
bool judge=true;//协同判断
int start;//保存最后一个单词的起始索引
string stmp;//用于剔除单词中多余的空格
if(s.empty()) return 0;
else
{
for(int i=0;i<s.size();i++)
{
if(s[i]!=' ' && judge) { start=i; judge=false; }
else if(s[i]==' ') judge=true;
}
stmp.assign(s,start);
#if 0
for(int j;j<stmp.size();j++)
{
if(stmp[j]==' ') stmp.erase(j,1);
}
#endif
stmp.erase(remove(stmp.begin(),stmp.end(),' '),stmp.end());
return stmp.size();
}
}
};
6.最大字母
其实代码很简单,但是难点在于理解题目。
翻译一下题目:给一个字符串,返回一个字符串。判断返回值条件:若输入中存在同一字母的大小写,且该大写字母的ascii码最大,则返回该大写字母字符串;否则返回"NO"
。
class Solution {
public:
/**
* @param s: a string
* @return: a string
*/
string largestLetter(string &s) {
// write your code here
//先找出大写字母最大,然后判断是否对应小写
char up='A';
bool ju,jl;
ju=false;jl=false;
string re;//返回值
for(int i=0;i<s.size();i++)
{
if(s[i]>='a' && s[i]<='z') continue;
else { up=up>s[i]?up:s[i]; ju=true;}
}
if(ju)
{
for(int j=0;j<s.size();j++)
{
if(up+32==s[j]) { re.push_back(up); return re; }
else jl=false;
}
if(!jl) return "NO";
}
else return "NO";
}
};
7.旋转字符串
类似[学习笔记-C++篇]day11 lintcode50中的翻转字符串。
class Solution {
public:
/**
* @param s: An array of char
* @param offset: An integer
* @return: nothing
*/
void rotateString(vector<char> &s, int offset) {
int k=offset%s.size();
string stmp;
for(int i=0;i<s.size();i++)
{
stmp.push_back(s[i]);
}
if(s.size()==0 || k==0) return;
else
{
stmp=stmp.substr(s.size()-k)+stmp.substr(0,s.size()-k);
s.assign(stmp.begin(),stmp.end());
}
}
};
思路应该是没问题的,但测试用例""
,会报错。
8.二阶阶乘
用到向上取整函数ceil
,n=ceil(num);
,注意为了保证num
为小数要用double
类型。
class Solution {
public:
/**
* @param n: the given number
* @return: the double factorial of the number
*/
long long doubleFactorial(int n) {
// Write your code here
long long op=1;
int tmp=n;
for(int i=0;i<n/2;i++)
{
op*=tmp;
tmp-=2;
}
return op;
}
};
9.实现栈
需要整理栈类的用法。应该会整理在STL教程
中。
在这边我采用了vector
,比较熟悉。但是空间消耗很大。
class Stack {
public:
/*
* @param x: An integer
* @return: nothing
*/
vector<int> test;
void push(int x) {
// write your code here
test.push_back(x);
}
/*
* @return: nothing
*/
void pop() {
// write your code here
test.pop_back();
}
/*
* @return: An integer
*/
int top() {
// write your code here
return test[test.size()-1];
}
/*
* @return: True if the stack is empty
*/
bool isEmpty() {
// write your code here
if(test.size()==0) return true;
else return false;
}
};
10.队列维护
class MyQueue {
public:
/*
* @param item: An integer
* @return: nothing
*/
deque<int> l;
void enqueue(int item) {
// write your code here
l.push_back(item);
}
/*
* @return: An integer
*/
int dequeue() {
// write your code here
int tmp=l.front();
l.pop_front();
return tmp;
}
};
11.有效的括号序列
首先不论对错,先说下思路。
把string
转到stack
中,然后对每一位字符判断,如果是三种左括号之一,判断下一位是不是对应右括号,是就pop()
2次,索引后移2位;不是,索引后移1位;不是左括号也右移1位索引。最后判断stack
的size()
。
class Solution {
public:
/**
* @param s: A string
* @return: whether the string is a valid parentheses
*/
bool isValidParentheses(string &s) {
// write your code here
stack<char> ss;
for(auto c:s) ss.push(c);
for(int i=0;i<s.size();)
{
switch(s[i])
{
case '(' : {if(s[i+1]==')') {ss.pop();ss.pop();i+=2;break;} i++;break;}
case '[' : {if(s[i+1]==']') {ss.pop();ss.pop();i+=2;break;} i++;break;}
case '{' : {if(s[i+1]=='}') {ss.pop();ss.pop();i+=2;break;} i++;break;}
default: i++;break;
}
}
if(ss.size()==0) return true;
else return false;
}
};
但是,题目不是说必须得()[]{}
吗,怎么([])
也对??
所以还需要考虑交叉出现的矛盾。就需要重新生成右括号,然后判断消去的时候会不会有间隔其他符号。
class Solution {
public:
/**
* @param s: A string
* @return: whether the string is a valid parentheses
*/
bool isValidParentheses(string &s) {
// write your code here
stack<char> ss;
for(auto c:s)
{
switch(c)
{
case '(': ss.push(')');break;
case '[': ss.push(']');break;
case '{': ss.push('}');break;
default:
if(ss.empty() || ss.top()!=c)
return false;
ss.pop();
break;
}
}
return ss.size()==0;
}
};
12.小括号匹配
和上一题一样。
不要为了偷懒用什么string s(string);
这种啊,输入参数和类型名重复了,会报错。
class Solution {
public:
/**
* @param string: A string
* @return: whether the string is valid
*/
bool matchParentheses(string &string) {
// write your code here
stack<char> ss;
for(auto c:string)
{
switch(c)
{
case '(': ss.push(')'); break;
case '[': ss.push(']'); break;
case '{': ss.push('}'); break;
default:
if(ss.empty() || c!=ss.top())
return false;
ss.pop();
break;
}
}
return ss.size()==0;
}
};
13.斐波那契数列
class Solution {
public:
/**
* @param n: an integer
* @return: an ineger f(n)
*/
int fibonacci(int n) {
// write your code here
int l,r,t;
if(n==1) return 0;
if(n==2) return 1;
for(int i=0;i<n;i++)
{
if(i==0) { l=0; continue;}
if(i==1) { r=1; continue;}
t=l+r;
l=r;
r=t;
}
return t;
}
};
用递归:
class Solution {
public:
int fibonacci(int n) {
if (n <= 2) {
return n - 1;
}
int fib[2];
fib[0] = 0;
fib[1] = 1;
for (int i = 2; i < n; i++) {
fib[i % 2] = fib[0] + fib[1];
}
return fib[(n+1)%2];
}
};
构建递归函数:
参考:解题思路
这里的思路是从最后一个往前递推到最初的2个数。然后一步步加起来。
class Solution {
public:
int dfs(int n, int fib[]) {
if (fib[n] != -1) {
return fib[n];
}
if (n <= 2) {
fib[n] = n - 1;
return fib[n];
}
fib[n] = dfs(n - 1, fib) + dfs(n - 2, fib);
return fib[n];
}
int fibonacci(int n) {
int result[n + 1];
for (int i = 0; i <= n; i++) {
result[i] = -1;
}
dfs(n, result);
return result[n];
}
};
14.二叉树的遍历
前序:根左右
中序:左根右
后序:左右根
先临时整理一下。
TreeNode
类型:
TreeNode *root;
root->left 取左子
root->right 取右子
root->val 取root中的值
root!=nullptr 判断指针是否为空
class TreeNode {
public:
int val;
TreeNode *left, *right;
TreeNode(int val) {
this->val = val;
this->left = this->right = NULL;
}
}
注意:
1)使用root
指针,结合->
2)调用递归函数,要记得给数组加上引用符&
3)判断指针是否为空的时候,要把!
符号和判空指令root->nullptr
分开
14.1 前序遍历
/**
* Definition of TreeNode:
* class TreeNode {
* public:
* int val;
* TreeNode *left, *right;
* TreeNode(int val) {
* this->val = val;
* this->left = this->right = NULL;
* }
* }
*/
class Solution {
public:
/**
* @param root: A Tree
* @return: Preorder in ArrayList which contains node values.
*/
void dps(TreeNode *r,vector<int> &p)
{
p.push_back(r->val);
if(!(r->left==nullptr)) dps(r->left,p);
if(!(r->right==nullptr)) dps(r->right,p);
}
vector<int> inorderTraversal(TreeNode *root) {
// write your code here
vector<int> post;
if(!(root==nullptr)) dps(root,post);
return post;
}
};
后台又抽了。
14.2 中序遍历
/**
* Definition of TreeNode:
* class TreeNode {
* public:
* int val;
* TreeNode *left, *right;
* TreeNode(int val) {
* this->val = val;
* this->left = this->right = NULL;
* }
* }
*/
class Solution {
public:
/**
* @param root: A Tree
* @return: Inorder in ArrayList which contains node values.
*/
void dps(TreeNode *r,vector<int> &p)
{
if(!(r->left==nullptr)) dps(r->left,p);
p.push_back(r->val);
if(!(r->right==nullptr)) dps(r->right,p);
}
vector<int> inorderTraversal(TreeNode *root) {
// write your code here
vector<int> post;
if(!(root==nullptr)) dps(root,post);
return post;
}
};
14.3 后序遍历
/**
* Definition of TreeNode:
* class TreeNode {
* public:
* int val;
* TreeNode *left, *right;
* TreeNode(int val) {
* this->val = val;
* this->left = this->right = NULL;
* }
* }
*/
class Solution {
public:
/**
* @param root: A Tree
* @return: Postorder in ArrayList which contains node values.
*/
void dps(TreeNode *r,vector<int> &p)
{
if(!(r->left==nullptr)) dps(r->left,p);
if(!(r->right==nullptr)) dps(r->right,p);
p.push_back(r->val);
}
vector<int> postorderTraversal(TreeNode *root) {
// write your code here
vector<int> post;
if(!(root==nullptr)) dps(root,post);
return post;
}
};
15.阶段性完结
纪念一下,虽然47/50=78%,虽然没完成3道是因为超时无法运行或后台问题,虽然菜,但是要纪念一下。