class Solution {
public:
vector<vector<int>> calcYangHuisTriangle(int n) {
vector<vector<int>> res;
vector<int> last;
last.push_back(1);
if (n==0) return res;
res.push_back(last);
if (n==1) return res;
for (int i=1;i<n;i++) {
vector<int> now;
for (int j=0;j<=last.size(); j++) {
if (j==0 ||j==last.size()) { now.push_back(1); continue; }
now.push_back(last[j]+last[j-1]);
}
res.push_back(now);
last=now;
}
return res;
}
};
1354. 杨辉三角形II
空间复杂度O(k),只用一个数组反复迭代,前后加0即可。
class Solution {
public:
vector<int> getRow(int rowIndex) {
// write your code here
vector<int> last={0,1,0};
if (rowIndex==0) return vector<int>(last.begin()+1,last.end()-1);
for (int i=0;i<rowIndex;i++) {
for (int j=0;j<last.size()-1; j++) {
last[j]=last[j]+last[j+1];
}
//后面的0仍保留,前面的0再加上
last.insert(last.begin(),0);
}
return vector<int>(last.begin()+1,last.end()-1);
}
};
1369. 最频繁单词
细节很多,transform(paragraph.begin(),paragraph.end(),paragraph.begin(),::tolower) 转成小写,注意字符串尾没有空格也要记录单词。
class Solution {
public:
string mostCommonWord(string ¶graph, vector<string> &banned) {
if (paragraph.size()==0) return "";
transform(paragraph.begin(),paragraph.end(),paragraph.begin(),::tolower);
unordered_set<string> banned_word;
unordered_map<string,int> word_freq;
for (int i=0;i<banned.size();i++) banned_word.insert(banned[i]);
int i=0;
string word="";
int max_freq=0;
string res="";
while (i<=paragraph.size()) {
if (paragraph[i]>='a' && paragraph[i]<='z') {
word=word+paragraph[i];
}
else if (paragraph[i]==' ' ||i==paragraph.size()){
if (banned_word.count(word)==0){
if (word_freq.count(word)>0) word_freq[word]++;
else word_freq[word]=1;
if (word_freq[word]>max_freq) {
max_freq=word_freq[word];
res=word;
}
}
word="";
}
i++;
}
return res;
}
};
1227. 重复的子串模式
一开始的思路是,模式串最少是由两个重复串组成的,最少是有1个字符组成,所以暴力搜索所有可能子串,以第一个假定子串为标准,后面的如果和它都一样说明是重复的字串模式。
class Solution {
public:
bool repeatedSubstringPattern(string &s) {
// write your code here
if (s=="") return false;
int n=s.length();
for (int i=n/2;i>=1;i--) {
if (n%i!=0) continue;
string base=s.substr(0,i);
int j;
for (j=i;j<n;j++)
if (s[j]!=base[j%i]) break;
if (j==n) return true;
}
return false;
}
};
比较牛逼的方法:对于一个模式串组成的字符串s,其模式串的长度最长为s的一半,即在s是由模式串组成的前提下时,s中至少包含两部分相同的模式串,那么s + s则至少包含四部分的模式串,如果去掉s + s中的第一个和最后一个字符,此时仍存在两个相邻的模式串,如果在r = (s + s)[1...-1]中能够找到s,说明原始的s是由模式串组成的。
注意字符串中搜索子串的方法:source.find(target)!=string::npos
class Solution {
public:
bool repeatedSubstringPattern(string s) {
string r = s.substr(1) + s.substr(0, s.size() - 1);
return r.find(s) != string::npos;
}
};
1746. 二叉搜索树结点最小距离
一开始想麻烦了,觉得最小距离只能在相邻两层出现,写了个层序遍历。但是类似[4,1,#,#,3]就不对。所以只能遍历整棵树,把值记录下来,然后在相邻两数间找最小值。也可以记录前一个遍历的值,尽量少占用内存空间。但是要注意跟着函数递归的话要写成指针,否则这个值记录在栈里会不停的变。
class Solution {
private:
int res;
public:
void help (TreeNode * root,int* last_val) {//接收的也是指针
if (root==NULL) return;
help(root->left,last_val);
if (*last_val!=-1) res=min(res,abs((*last_val)-root->val));//*是取指针指向的值
*last_val=root->val;//改里面的值加*
help(root->right,last_val);
}
int minDiffInBST(TreeNode * root) {
// Write your code here.
if (root==NULL) return 0;
res=INT_MAX;
int* last=new int(-1);//新建一个叫last的指针指向一片内存
help(root,last);//传指针
return res;
}
};
或者用&,这里也有说明https://blog.youkuaiyun.com/musechipin/article/details/62221330
class Solution {
private:
int res;
public:
void help (TreeNode * root,int &last_val) {//新建一个传过来的last的引用(不要理解成取地址),last和last_val都指向同一片内存
if (root==NULL) return;
help(root->left,last_val);//再调用的时候,新函数会新建一个last_val的引用,可能有很多引用,但是指向的内存都是一样的,保证了这个数不随递归改变
if (last_val!=-1) res=min(res,abs((last_val)-root->val));
last_val=root->val;
help(root->right,last_val);
}
int minDiffInBST(TreeNode * root) {
// Write your code here.
if (root==NULL) return 0;
res=INT_MAX;
int last=-1;
help(root,last);//传一个数
return res;
}
};
1187. 数组中的K-diff对
这个题有个坑是,别的数字都可以使用多次只要有就可以,但k=0的时候必须有至少两个相同的数才行(自己和自己不行)
class Solution {
public:
int findPairs(vector<int> &nums, int k) {
// Write your code here
if (nums.size()<=0) return 0;
unordered_map<int,int> record;
for (int i=0;i<nums.size();i++) {
if (record.count(nums[i])!=0) record[nums[i]]++;
else record[nums[i]]=1;
}
int res=0;
for (auto number:record)
if (record.count(number.first+k)>0) {
if (k!=0) res++;
if (k==0 && record[number.first]>1) res++;
}
return res;
}
};
或者使用双指针的方法,j从i后一位开始(保证不会出现1个数用两次),i每次向后移动一个数,j可以连续向后移动(不用走回头路,因为排序之后i向后移则差变小,j不可能向前移)
class Solution{
public:
int findPairs(vector<int> &nums, int k)
{
int n = nums.size();
sort(nums.begin(), nums.end());
int ans = 0;
for (int i = 0, j = 0; i < n; i++)
{
if (i == j)
j++;
while (i + 1 < n && nums[i] == nums[i + 1])
i++;
while (j + 1 < n && nums[j] == nums[j + 1])
j++;
while (j < n && abs(nums[j] - nums[i]) < k)
j++;
if (abs(nums[j] - nums[i]) == k)
{
ans++;
j++;
}
}
return ans;
}
};
1137. 从二叉树构建字符串
这个题一个是注意string和int的互转,用stringstream,还有一个是注意它说的,缺省的才能省略,就是叶子结点的左右子树可以省略,左子树可以省略,但是右子树是空必须加()。
class Solution {
public:
void help(TreeNode * t, string& s) {
if (t==NULL) return;
stringstream ss;
string tmp;
ss<<t->val;
ss>>tmp;
s=s+tmp;
if (t->left==NULL && t->right==NULL) return;
s=s+'(';
help(t->left,s);
s=s+')';
if (t->right!=NULL){
s=s+'(';
help(t->right,s);
s=s+')';
}
}
string tree2str(TreeNode * t) {
// write your code here
if (t==NULL) return NULL;
string s="";
help(t,s);
return s;
}
};
判断给定单词列表能否首位链接
讨论:https://bbs.youkuaiyun.com/topics/70505395
1.需要构建有向图,有两种方法,一种是词作为点,一种是词首和词尾分别是两个点,有词则相连(这种明显时间复杂度会低很多);
2.宽度优先搜索只能判断图是不是全连通(弱联通),要想判断能否一条路径走完需要补充验证欧拉回路(欧拉路径)的条件
3.或者使用深度优先搜索,但是会会报错,推测是时间复杂度太高
以下代码是宽搜代码,测试case全过了,但实际需要补全欧拉路径验证条件,即每个点出入度相等,允许有一个点入度少1,一个点入度多1。
#include <unordered_map>
#include <set>
#include <queue>
using namespace std;
int try_con(string head, unordered_map<string,set<string>> relation) {
set<string> v;
v.insert(head);
queue<string> h;
h.push(head);
while (!h.empty()) {
int l=h.size();
for (int i=0;i<l;i++) {
string f=h.front();
h.pop();
for (auto w:relation[f])
if (v.find(w)==v.end()) {
v.insert(w);
h.push(w);
}
}
}
return v.size();
}
int canArrangeWords(int num,char** arr){
// WRITE YOUR CODE HERE
if (num<=1) return 1;
unordered_map<string,set<string>> relation;
for (int i=0;i<num;i++) {
string tmp1=arr[i];
set<string> tmp;
for (int j=0;j<num;j++) {
if (i==j) continue;
string tmp2=arr[j];
if (tmp1[tmp1.length()-1]==tmp2[0])
tmp.insert(tmp2);
}
relation[tmp1]=tmp;
}
for (int i=0;i<num;i++) {
string head=arr[i];
if (try_con(head,relation)==num) return 1;
}
return -1;
}
1333. 颠倒二进制位
两种算法,一种是短除法:
class Solution {
public:
/**
* @param n: an integer
* @return: return an integer
*/
long long reverseBits(long long n) {
// write your code here
long long res=0;
long long base=pow(2,31);
while (n>0) {
res=res + (n%2==1?base:0);
n=n/2;
base=base/2;
}
return res;
}
};
一种位运算:
class Solution {
public:
/**
* @param n: an integer
* @return: return an integer
*/
long long reverseBits(long long n) {
// write your code here
long long m=0;
for (int i=0;i<32;i++) {
m=m<<1;//先移一位的原因是第一位是符号位
m=m | (n &1);
n=n>>1;
}
return m;
}
};