leetcode Ch3-DFS & Backtracking II
class Solution
{
public:
vector<int> grayCode(int n)
{
vector<int> result={};
if(n==) return result;
return dfs(n);
}
vector<int> dfs(int n)
{
if(n==)
{
vector<int> v={,};
return v;
}
vector<int> tmp=dfs(n-);
int len=tmp.size();
for(int i=len-;i>=;i--)
{
tmp.push_back(tmp[i]+len);
}
return tmp;
}
};
这个方法主要是利用对称性。但是性能上并不是太好。最优解法应该是利用位运算。参考此代码中的第一个评论。
需要注意,在n=0时返回的不是空vector,而是{0}.
update 8.13
class Solution {
public:
vector<string> generateParenthesis(int n) {
vector<string> res;
string tmp;
string brackets("()");
dfs(res, tmp, n, , , brackets);
return res;
} void dfs(vector<string>& res, string tmp, int n, int left, int right, string brackets) {
if (left == n && right == n) {
res.push_back(tmp);
return;
}
for (int i = ; i < brackets.size(); i++) {
if ((i == && left <= right) || (left == n && i == )) {
continue;
}
tmp += brackets[i];
if (i == ) {
dfs(res, tmp, n, left + , right, brackets);
} else {
dfs(res, tmp, n, left, right + , brackets);
}
tmp.pop_back();
}
}
};
按照之前的套路来写的。就是对于dfs的for循环而言,应当是对于同一个位置的所有可能情况来循环的。
写的有点繁琐。
class Solution
{
public:
vector<string> generateParenthesis(int n)
{
if(n==) return result;
finalPos=*n;
left=n;
right=n;
dfs();
return result;
}
void dfs(int n)
{
if(n==finalPos)
{
result.push_back(tmp);
return;
}
if(dif> && right>)
{
right--;
dif--;
tmp+=')';
dfs(n+);
tmp.resize(tmp.size()-);
right++;
dif++;
}
if(left>)
{
left--;
dif++;
tmp+='(';
dfs(n+);
tmp.resize(tmp.size()-);
left++;
dif--;
}
}
int finalPos;
int dif=;
string tmp;
int left;
int right;
vector<string> result;
};
下面的代码参考于此。非常巧妙,简洁。
class Solution {
public:
vector<string> generateParenthesis(int n) {
vector<string> res;
addingpar(res, "", n, );
return res;
}
void addingpar(vector<string> &v, string str, int n, int m){
if(n== && m==) {
v.push_back(str);
return;
}
if(m > ){ addingpar(v, str+")", n, m-); }
if(n > ){ addingpar(v, str+"(", n-, m+); }
}
};
三、Permutation
1. Permutations
class Solution
{
public:
vector<vector<int>> permute(vector<int> &num)
{
dfs(num);
return result;
}
private:
vector<vector<int>> result;
vector<int> path;
void dfs(vector<int> &num)
{
if(path.size()==num.size())
{
result.push_back(path);
return;
}
for(int i=;i<num.size();i++)
{
if(find(path.begin(),path.end(),num[i])==path.end())
{
path.push_back(num[i]);
dfs(num);
path.pop_back();
}
}
}
};
refer to soulMach.中规中矩,可以一用。
class Solution
{
public:
vector<vector<int>> permute(vector<int> &nums)
{
len=nums.size();
vector<vector<int>> result;
for(int i=;i<nums.size();i++)
umap[nums[i]]=;
helper(result,umap,);
return result;
}
void helper(vector<vector<int>> &result,unordered_map<int,int> &umap,int n)
{
if(n==len)
{
result.push_back(tmp);
return;
}
for(auto it=umap.begin();it!=umap.end();it++)
{
if(it->second==)
{
tmp.push_back(it->first);
umap[it->first]=;
helper(result,umap,n+);
umap[it->first]=;
tmp.resize(tmp.size()-);
}
}
}
int len;
unordered_map<int,int> umap;
vector<int> tmp;
};
中规中矩的做法。不过多分配了一个umap.
class Solution {
public:
vector<vector<int> > permute(vector<int> &num) {
vector<vector<int> > result;
permuteRecursive(num, , result);
return result;
}
void permuteRecursive(vector<int> &num, int begin, vector<vector<int> > &result) {
if (begin >= num.size()) {
result.push_back(num);
return;
}
for (int i = begin; i < num.size(); i++) {
swap(num[begin], num[i]);
permuteRecursive(num, begin + , result);
swap(num[begin], num[i]);
}
}
};
class Solution
{
public:
vector<vector<int>> permuteUnique(vector<int> &nums)
{
for(auto n:nums)
umap[n]++;
dfs(nums);
return result;
}
private:
vector<vector<int>> result;
vector<int> path;
unordered_map<int,int> umap;
void dfs(vector<int> &nums)
{
if(path.size()==nums.size())
{
result.push_back(path);
return;
}
for(auto p:umap)
{
if(p.second>)
{
path.push_back(p.first);
umap[p.first]--;//不能用p.second--.因为p是临时变量,影响不到umap。
dfs(nums);
umap[p.first]++;
path.pop_back();
}
}
}
};
注意:老是会忘刚开始时初始化umap!
比较奇怪的是,在dfs函数里,如果把对umap遍历改为对vector num遍历,就会TLE。
这里还遇到一个问题,就是我一开始遍历umap时用的是for(auto p:umap),然后对p.second做修改后是影响不到umap[p.first]的。因为这里的p相当于一个临时变量,无法影响umap的映射关系。如果换成指针的话就可以了。
对比两个permute。
对于不含重复元素的permute,如果以前没用过该元素,就可以用。即需要判定下path中是否含有该元素。若没有,即可用之。
对于含有重复元素的permute,借助于umap存储每个元素的个数。dfs时遍历umap,只要umap中该元素个数大于0,就可以用之。
四、Combination & Subset
1. Combinations
class Solution
{
public:
vector<vector<int>> combine(int n, int k)
{
dfs(n, k, );
return result;
}
private:
vector<vector<int>> result;
vector<int> path;
void dfs(int n, int k, int start)
{
if (path.size() == k)
{
result.push_back(path);
return;
}
for (int i = start; i <= n; i++)
{
// if (find(path.begin(), path.end(), i) == path.end())
path.push_back(i);
dfs(n, k, i+ );//dfs(n, k, start + 1);
path.pop_back();
}
}
};
在combination里,和permutation不同的地方在于,为了保证不会出现重复,遍历的时候按照升序来,即后一个数一定要大于前一个数。
同时,由于保证了后一个数必定比前一个数大,那么其实就保证了唯一性,也就不用find去判断是否在path里出现过了。
另外注意for循环的i是从start开始,而next dfs里的start是取的i+1而不是start+1.
2. Subsets
递归版:
[Templated]
class Solution
{
public:
vector<vector<int>> subsets(vector<int> &nums)
{
sort(nums.begin(),nums.end());
dfs(nums,);
return result;
}
vector<vector<int>> result;
vector<int> path;
void dfs(vector<int> &nums,int start)
{
result.push_back(path);
for(int i=start;i<nums.size();i++)
{
path.push_back(nums[i]);
dfs(nums,i+);
path.pop_back();
}
}
};
该模板化版本和combination与subsets II都很类似。它和combination的区别在于,dfs函数一开始不需要判断长度就压入result,因为它不需要在乎长度。
和subsets II的区别在于,不用判重。
版本2:
class Solution
{
public:
vector<vector<int>> subsets(vector<int> &nums)
{
sort(nums.begin(),nums.end());
dfs(nums,);
return result;
}
vector<vector<int>> result;
vector<int> path;
void dfs(vector<int> &nums, int step)
{
if(step==nums.size())
{
result.push_back(path);
return;
}
path.push_back(nums[step]);
dfs(nums,step+);
path.pop_back();
dfs(nums,step+);
}
};
一开始打算利用combinations,即依次指定combination的长度。但是那样很繁琐。
需要注意的是Elements in a subset must be in non-descending order。所以在操作之前需要先sort一下;
迭代版:
class Solution
{
public:
vector<vector<int>> subsets(vector<int> &nums)
{
vector<vector<int>> result(,vector<int>());
sort(nums.begin(),nums.end());
for(int i=;i<nums.size();i++)
{
int n=result.size();
for(int j=;j<n;j++)
{
result.push_back(result[j]);
result.back().push_back(nums[i]);
}
}
return result;
}
};
基本思路就是每次循环都把当前vector已有的子集合拷贝一份并在末尾添加一个新元素。再加入到vector里。比如对于{1,2,3},就先加入空,然后复制一下空并末尾添加1(当前子集合即为{空,{1}}),然后把空和{1}再各拷贝一份并在末尾添上2(即{2},{1,2}),并加入原vector。子集合变成了{空,{1},{2},{1,2}},再拷贝一份当前vector所有内容并在各自末尾添上3({3},{1,2},{2,3},{1,2,3}),并加入到vector里,变成(空,{1},{2},{1,2}, {3},{1,2},{2,3},{1,2,3})。
用二进制法也可以让空间复杂度降为O(1),参考soulMach。
3. Subsets II
class Solution
{
public:
vector<vector<int>> subsetsWithDup(vector<int> &nums)
{
sort(nums.begin(),nums.end());
dfs(nums,);
return result;
}
vector<vector<int>> result;
vector<int> path;
void dfs(vector<int> &nums, int start)
{
result.push_back(path);
for(int i=start;i<nums.size();i++)
{
if(i!=start && nums[i]==nums[i-]) continue;
path.push_back(nums[i]);
dfs(nums,i+);
path.pop_back();
}
}
};
在产生path时,path的任何一个确定的位置(如第3个位置,第5个位置),都不选相同值的元素,这样就能防止结果中有重复。
那怎么叫确定的位置呢?在代码Line15的for循环里,遍历的每个元素都处于同一层,它们都是将要放置在或不放置在某一个相同的位置。(这里的位置值得是结果path中的位置,比如{1,2,3}这个path,第2个位置是2,第3个位置是3.) for 循环里的每个元素都是面临对同一个位置做取舍决定。
每嵌套调用一个dfs,就走的更深一层,体现在path的位数增加1. 类似于:
dfs
{//现在path长度为1
dfs
{//现在path长度为2
dfs
{//现在path长度为3
......
}
//现在path长度又恢复为2.继续遍历for循环的下一元素来填充path
......
}
//现在path长度又恢复为1.继续遍历for循环的下一元素来填充path
......
}
回头去看,该算法就是保证了相同深度的path的末尾元素不选取选过的元素。所以可以通过在dfs里加个for循环(并且循环内部加个判断去重)来实现。
class Solution
{
public:
vector<vector<int>> combinationSum(vector<int> &candidates,int target)
{
sort(candidates.begin(),candidates.end());
dfs(candidates,,,target);
return result;
}
vector<vector<int>> result;
vector<int> path;
void dfs(vector<int> &nums, int start,int sum,int target)
{
if(sum>target) return;
if(sum==target)
{
result.push_back(path);
return;
}
for(int i=start;i<nums.size();i++)
{
path.push_back(nums[i]);
dfs(nums,i,sum+nums[i],target);
path.pop_back();
}
}
};
class Solution
{
public:
vector<vector<int>> combinationSum2(vector<int> &candidates,int target)
{
sort(candidates.begin(),candidates.end());
dfs(candidates,,,target);
return result;
}
vector<vector<int>> result;
vector<int> path;
void dfs(vector<int> &nums, int start,int sum,int target)
{
if(sum>target) return;
if(sum==target)
{
result.push_back(path);
return;
}
for(int i=start;i<nums.size();i++)
{
if(i!=start && nums[i]==nums[i-]) continue;
path.push_back(nums[i]);
dfs(nums,i+,sum+nums[i],target);
path.pop_back();
}
}
};
Combination sum II 比 I 就多在加一个判重。和之前subsets II 比 I 多一句判重是一样的。
class Solution
{
public:
vector<vector<int>> combinationSum3(int k,int n)
{
vector<int> nums={,,,,,,,,};
dfs(nums,k,n,,);
return result;
}
vector<vector<int>> result;
vector<int> path;
void dfs(vector<int> &nums,int k,int n,int start,int sum)
{
if(sum==n && path.size()==k)
{
result.push_back(path);
return;
}
if(sum>n||path.size()>=k) return;
for(int i=start;i<nums.size();i++)
{
path.push_back(nums[i]);
dfs(nums,k,n,i+,sum+nums[i]);
path.pop_back();
}
}
};
判断的时候多了个限制条件,需要既让sum相等同时也要让path.size()等于k。
小结:对于combination,subset这种题,元素顺序不同不能作为区分点(不像permutation那样)。因此为了防止dfs时会出现{1,2}和{2,1}这种,需要借助start这个机制来确保下一个将要遍历的元素在位置上必须在上一个遍历的元素之后。
class Solution
{
public:
vector<vector<string>> partition(string s)
{
dfs(,s);
return result;
}
vector<vector<string>> result;
vector<string> path;
void dfs(int start,string &s)
{
if(start==s.length())
{
result.push_back(path);
return;
}
for(int i=start;i<s.length();i++)
{
if(isPalindrome(s.substr(start,i-start+)))
{
path.push_back(s.substr(start,i-start+));
dfs(i+,s);
path.pop_back();
}
}
}
bool isPalindrome(string s)
{
if(s.empty()) return true;
int len=s.length();
for(int i=;i<len/;i++)
{
if(s[i]!=s[len-i-])
return false;
}
return true;
}
};
注意Line34,是s[len-1-i],不是s[len-i].
Palindrome Partitioning有DP解法。后序补充上。
六、Letter Combinations of a Phone Number
class Solution
{
public:
vector<string> letterCombinations(string digits)
{
if(digits.empty()) return result;
initialization();
dfs(digits,);
return result;
}
private:
vector<string> result;
string path;
unordered_map<int,string> umap;
void dfs(string s,int step)
{
if(path.size()==s.size())
{
result.push_back(path);
return;
}
string tmp=umap[int(s[step]-'')];
for(int i=;i<tmp.size();i++)
{
path.push_back(tmp[i]);
dfs(s,step+);
path.pop_back();
}
}
void initialization()
{
umap[]="abc";
umap[]="def";
umap[]="ghi";
umap[]="jkl";
umap[]="mno";
umap[]="pqrs";
umap[]="tuv";
umap[]="wxyz";
umap[]=" ";
}
};
注意:Line6!这种corner case要格外小心!
class Solution
{
public:
string getPermutation(int n,int k)
{
string result(n,' ');
string s("");
string str=s.substr(,n);
k--;
for(int i=;i<n;i++)
{
int tmp=factorial(str.size()-);
int q=k/tmp;
result[i]=str[q];
str.erase(q,);
k-=tmp*q;
}
return result;
}
int factorial(int n)
{
if(n==) return ;
int result=;
for(int i=;i<=n;i++)
result*=i;
return result;
}
};
主要利用康托展开。康托展开详细内容参见此文。
八、Sudoku
class Solution
{
public:
void solveSudoku(vector<vector<char>> &board)
{
dfs(board,);
}
bool dfs(vector<vector<char>> &board, int pos)
{
if(pos>=) return true;
int row=pos/;
int col=pos%;
if(board[row][col]!='.')
return dfs(board,pos+);
else
{
for(char c='';c<='';c++)
{
if(check(board,row,col,c))
{
board[row][col]=c;
if(dfs(board,pos+)) return true;
else board[row][col]='.';
}
}
return false;
}
}
bool check(vector<vector<char>> &board, int row,int col,char value)
{
for(int i=;i<;i++)
if(board[row][i]==value) return false;
for(int i=;i<;i++)
if(board[i][col]==value) return false;
for(int i=;i<;i++)
{
int r=row/*+i/;
int c=col/*+i%;
if(board[r][c]==value) return false;
}
return true;
}
};
注意一些技巧。Line11,12通过对board.size取余和取商,将二维的遍历转化为一维的遍历,每次只需pos++即可。
Line37,38也类似,对每个方块遍历时,(row/3*3,col/3*3)能得到坐标为(row,col)的点所在的方块的左上角的点对应的坐标。
2. Valid Sudoku
class Solution {
public:
bool isValidSudoku(vector<vector<char>> &board)
{
vector<bool> mark(,false);
for(int i=;i<;i++)
{
fill(mark.begin(),mark.end(),false);
for(int j=;j<;j++)
{
if(board[i][j]=='.') continue;
if(mark[board[i][j]-'']==true) return false;
mark[board[i][j]-'']=true;
}
}
for(int j=;j<;j++)
{
fill(mark.begin(),mark.end(),false);
for(int i=;i<;i++)
{
if(board[i][j]=='.') continue;
if(mark[board[i][j]-'']==true) return false;
mark[board[i][j]-'']=true;
}
}
for(int i=;i<;i+=)
{
for(int j=;j<;j+=)
{
fill(mark.begin(),mark.end(),false);
for(int k=;k<;k++)
{
int row=i+k/;
int col=j+k%;
if(board[row][col]=='.') continue;
if(mark[board[row][col]-'']==true) return false;
mark[board[row][col]-'']=true;
}
}
}
return true;
}
};
分别从行,列,块的角度来check是否符合valid。(不是DFS类的,只是因为同属于Sudoku问题所以放进来。)
class Solution
{
public:
vector<string> restoreIpAddresses(string s)
{
dfs(s,,);
return result;
}
vector<string> result;
string path;
void dfs(string s,int start,int step)
{
if (step == )
{
if (start == s.size())
result.push_back(path);
return;
}
for (int i = start; i < start + && i<s.size(); i++)
{
string tmp = s.substr(start, i - start + );
if (isValid(tmp))
{
path += tmp;
if (step < ) path += '.';
dfs(s,i+,step+);
path.resize(path.size()-tmp.size());
if (step < ) path.resize(path.size()-);
}
}
}
bool isValid(string s)
{
if (s.size() > && s[] == '') return false;
return (stoi(s) >= && stoi(s) <= );
}
};
第一遍做错了。除了标记start之外,还要记录当前partition几次了。超过4次就得return了。
十、Trie
1. Implement Trie (Prefix Tree)
class TrieNode
{
public:
char content;
bool isend;
int shared;
vector<TrieNode*> children;
TrieNode():content(' '),isend(false),shared(){}
TrieNode(char ch):content(ch),isend(false),shared(){}
TrieNode* subNode(char ch)
{
for(auto child:children)
{
if(child->content==ch)
return child;
}
return NULL;
}
~TrieNode()
{
for(auto child:children)
delete child;
}
}; class Trie
{
private:
TrieNode* root;
public:
Trie()
{
root=new TrieNode();
}
void insert(string s)
{
if(search(s)) return;
TrieNode* curr=root;
for(auto ch:s)
{
TrieNode* child=curr->subNode(ch);
if(child!=NULL)
curr=child;
else
{
TrieNode* newNode=new TrieNode(ch);
curr->children.push_back(newNode);
curr=newNode;
}
++curr->shared;
}
curr->isend=true;
}
bool search(string key)
{
TrieNode* curr=root;
for(auto ch:key)
{
curr=curr->subNode(ch);
if(curr==NULL) return false;
}
return curr->isend==true;
}
bool startsWith(string prefix)
{
TrieNode* curr=root;
for(auto ch:prefix)
{
curr=curr->subNode(ch);
if(curr==NULL) return false;
}
return true;
}
~Trie()
{
delete root;
}
};
2. Add and Search Word - Data structure design
class TrieNode
{
public:
char content;
vector<TrieNode*> children;
bool isend;
int shared;
TrieNode* subNode(char ch)
{
for(auto child:children)
if(child->content==ch) return child;
return NULL;
}
TrieNode():content(' '),isend(),shared(){}
TrieNode(char ch):content(ch),isend(),shared(){}
~TrieNode()
{
for(auto child:children)
delete child;
}
}; class WordDictionary
{
public:
void addWord(string word)
{
TrieNode* curr=root;
for(auto ch:word)
{
TrieNode* child=curr->subNode(ch);
if(child!=NULL)
curr=child;
else
{
TrieNode* newNode=new TrieNode(ch);
curr->children.push_back(newNode);
curr=newNode;
}
}
curr->isend=true;
}
bool search(string word)
{
return dfs(word,root);
}
bool dfs(string word,TrieNode* root)
{
if(word.empty()) return root->isend;
if(word[]=='.')
{
for(auto child:root->children)
if(dfs(word.substr(,word.size()-),child)==true)
return true;
return false;
}
else
{
TrieNode* curr=root->subNode(word[]);
if(curr==NULL) return false;
else return dfs(word.substr(,word.size()-),curr);
}
}
WordDictionary()
{
root=new TrieNode();
}
~WordDictionary()
{
delete root;
}
private:
TrieNode* root;
};
主要是需要处理有通配符'.'的情况,search函数修改了一下。其他跟Implement Trie一样。
十一、字符串匹配
1. Regular Expression Matching
class Solution
{
public:
bool isMatch(string s,string p)
{
return dfs(s,p,,);
}
bool dfs(string s,string p,int sStart,int pStart)
{
if(pStart==p.size()) return (sStart==s.size());
if(sStart>s.size()) return false;
if(p[pStart+]!='*')
{
if(p[pStart]==s[sStart]||(p[pStart]=='.'))
return dfs(s,p,sStart+,pStart+);
return false;
}
else
{
while(s[sStart]==p[pStart]||(p[pStart]=='.'&& sStart<s.size()))
{//相当于将x*替代为0~n个x
if(dfs(s,p,sStart,pStart+)==true)
return true;
sStart++;
}
return dfs(s,p,sStart,pStart+);//相当于将x*替代为0个x
}
}
};
主要是题意别理解错。正则表达式(Regex)和通配符(Wildcard)并不一样。通配符里的*是可以代表任意数量任意字符,而正则表达式里的*是指的*前面的字符可以连续重复使用任意次。正则表达式里的“.*”才等价于通配符里的“*”。
注意Line20最后,需要判断sStart<s.size()。
还有DP解法。在DP部分重做一遍。
class Solution
{
public:
bool isMatch(string s,string p)
{
return dfs(s,p,,);
}
bool dfs(string s,string p,int sStart,int pStart)
{
if(pStart==p.size()) return (sStart==s.size());
if(sStart>s.size()) return false;
if(p[pStart]!='*')
{
if(p[pStart]==s[sStart]||p[pStart]=='?')
return dfs(s,p,sStart+,pStart+);
return false;
}
else
{
while(sStart<s.size())
{
if(dfs(s,p,sStart,pStart+)==true) return true;
sStart++;
}
return dfs(s,p,sStart,pStart+);
}
}
};
参照上题模式来做。用dfs会TLE。但是对于面试应该可以用。
关于Line25存在的意义(不存在肯定不行,会返回一个乱七八糟的整数。因为运行到这里时没有合适的return语句,就会返回一个随便什么数。)思考一下这里的Line25以及上一道题里的。
我认为Line20 & 25可以替换为:
while (sStart <= s.size())
{
if (dfs(s, p, sStart, pStart + ) == true) return true;
sStart++;
}
return false;
因为Line25之所以执行是因为前面的while语句一直到循环结束都没有符合要求的情况出现。原来的代码中,while循环是while (sStart < s.size()),因此当sStart等于s.size()时,就会执行Line25的内容。由于sStart==s.size()时仍是可能符合条件的(如果此时pStart也等于p.size()的话),因此直接return dfs(s,p,sStart,pStart+1)去判断是否符合条件即可。如果把while循环改为while (sStart <= s.size()),退出循环时是sStart==s.size()+1时,此时必然不可能符合要求了。因此Line25就直接return false。
以上属猜测。目测是对的。有机会找别的oj检验一下。
关于非递归做法,参考此答案。回头做一下。
十二、
1. Word Search
class Solution
{
public:
bool exist(vector<vector<char>> &board,string word)
{
int m=board.size(),n=board[].size();
vector<vector<bool>> visited(m,vector<bool>(n,false));
for(int i=;i<m;i++)
{
for(int j=;j<n;j++)
{
if(dfs(board,word,i,j,visited,))
return true;
}
}
return false;
}
bool dfs(vector<vector<char>> &board,string word,int x,int y,vector<vector<bool>> &visited,int index)
{
if(index==word.size()) return true;
if(x<||y<||x>=board.size()||y>=board[].size()) return false;
if(visited[x][y]) return false;
if(board[x][y]!=word[index]) return false;
visited[x][y]=true;
bool result=dfs(board,word,x-,y,visited,index+)||dfs(board,word,x+,y,visited,index+)||
dfs(board,word,x,y-,visited,index+)||dfs(board,word,x,y+,visited,index+);
visited[x][y]=false;
return result;
}
};
refer to soulMach.
TO BE CONTINUED
leetcode Ch3-DFS & Backtracking II的更多相关文章
- LeetCode:路径总和II【113】
LeetCode:路径总和II[113] 题目描述 给定一个二叉树和一个目标和,找到所有从根节点到叶子节点路径总和等于给定目标和的路径. 说明: 叶子节点是指没有子节点的节点. 示例:给定如下二叉树, ...
- LeetCode Single Number I / II / III
[1]LeetCode 136 Single Number 题意:奇数个数,其中除了一个数只出现一次外,其他数都是成对出现,比如1,2,2,3,3...,求出该单个数. 解法:容易想到异或的性质,两个 ...
- [array] leetcode - 40. Combination Sum II - Medium
leetcode - 40. Combination Sum II - Medium descrition Given a collection of candidate numbers (C) an ...
- LeetCode 137. Single Number II(只出现一次的数字 II)
LeetCode 137. Single Number II(只出现一次的数字 II)
- LeetCode:组合总数II【40】
LeetCode:组合总数II[40] 题目描述 给定一个数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合. candi ...
- leetcode@ [126] Word Ladder II (BFS + 层次遍历 + DFS)
https://leetcode.com/problems/word-ladder-ii/ Given two words (beginWord and endWord), and a diction ...
- Leetcode总结之Backtracking
本文我们就Leetcode中的一个类型的题目backtracking进行一系列的总结和归纳.backtracking这个方法本质是建立在递归的基础上,不断尝试新的路径,这里关键是每次尝试完以后需要退回 ...
- LeetCode:Word Ladder I II
其他LeetCode题目欢迎访问:LeetCode结题报告索引 LeetCode:Word Ladder Given two words (start and end), and a dictiona ...
- LeetCode: Word Break I && II
I title: https://leetcode.com/problems/word-break/ Given a string s and a dictionary of words dict, ...
随机推荐
- Java集合类中的Iterator和ListIterator的区别
注意:内容来自网络他人文章! 最近看到集合类,知道凡是实现了Collection接口的集合类,都有一个Iterator方法,用于返回一个实现了Iterator接口的对象,用于遍历集合:(Iterato ...
- jni使用javap查看java类方法签名
在Jni开发中,需要回调给java层数据,因此使用java的方法签名是必不可少的. 快速定位java方法签名的方式: java方法签名由(函数参数列表)返回值组成. cmd运行:javap -s 字节 ...
- javac的访问者模式2
(5)Printer /** * A combined type/symbol visitor for generating non-trivial(有意义的) localized string * ...
- python-pymongo使用
#-*- coding: utf-8 -*- #python2.7x from pymongo import MongoClient def get_db(): #建立连接 client = Mong ...
- JavaScript数据结构-1.数组
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- k8s中secret解析
概览 Secret是用来保存小片敏感数据的k8s资源,例如密码,token,或者秘钥.这类数据当然也可以存放在Pod或者镜像中,但是放在Secret中是为了更方便的控制如何使用数据,并减少暴露的风险. ...
- 一文带你入门图像分析,成为AI专家不是梦!
欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 本文由腾讯云AI中心发表于云+社区专栏 腾讯云高级研究员讲述,从成像到图像分析如何入门 文︱冀永楠 "AI来了"邀请到我 ...
- 转换json和字符串的一些方法
将字符串转换成json对象的方法: var str = '{"name1":"value1","name2":"value2&qu ...
- 经典实用的iptables shell脚本
先解释一下iptables里的参数意思:A: 添加 (跟链)-I: 插入-p: 跟协议-s: 源IP-d: 目标IP-j: 操作行为-t: 加表--to-source:SNAT用,表示改成的SNAT源 ...
- tr td 移动变色
jsp <table id="tableList" class="table table-hover"></table> css .t ...