1、Same Tree
Given two binary trees, write a function to check if they are equal or not.
Two binary trees are considered equal if they are structurally identical and the nodes have the same value.
典型的递归树的问题。 bool isSameTree(TreeNode *p, TreeNode *q) {
if(p==NULL|q==NULL){
if(p!=q){
return false;
}
else
return true;
}
if(p!=q&&p->val==q->val){
return isSameTree(p->left,q->left)&&isSameTree(p->right,q->right);
}
else{
return false;
}
}
bool isSameTree(TreeNode *p, TreeNode *q) {
if(p==NULL|q==NULL){
if(p!=q){
return false;
}
else
return true;
}
if(p!=q&&p->val==q->val){
return isSameTree(p->left,q->left)&&isSameTree(p->right,q->right);
}
else{
return false;
}
}
2、Unique Binary Search Trees I II
Given n, how many structurally unique BST's (binary search trees) that store values 1...n?
For example,
Given n = 3, there are a total of 5 unique BST's.
1 3 3 2 1 \ / / / \ \ 3 2 1 1 3 2 / / \ \ 2 1 2 3也是递归的方式,从当前的数组中选出一个root,大于该root的push到右孩子,小于的则push到左孩子。动态规划来做,由于给定n个数,n个数组成的二叉树是一定的,那么,我们就可以这么来考虑了。记得当时这个也是参考别人的。
num(n) = num(i)+num(n-i);
int numTrees(int n) {//一维动态规划
if(n<=1){
return n;
}
int *way = new int[n+1];
way[0] = 1;
way[1] = 1;
for(int i = 2;i<=n;i++){
way[i]=0;
for(int left = 0;left<i;left++){
way[i]+=way[left]*way[i-1-left];
}
}
int ret = way[n];
delete way;
return way[n];
}
int numTrees(int n) {//一维动态规划
if(n<=1){
return n;
}
int *way = new int[n+1];
way[0] = 1;
way[1] = 1;
for(int i = 2;i<=n;i++){
way[i]=0;
for(int left = 0;left<i;left++){
way[i]+=way[left]*way[i-1-left];
}
}
int ret = way[n];
delete way;
return way[n];
}
Given n, generate all structurally unique BST's (binary search trees) that store values 1...n.
For example,
Given n = 3, your program should return all 5 unique BST's shown below.
1 3 3 2 1 \ / / / \ \ 3 2 1 1 3 2 / / \ \ 2 1 2 3这次是寻找BST,将i-j形成的所有二叉树存入vector,这就是动态规划的中间数组。然后后面的继续添加。
vector<TreeNode *> generate(int s,int e){
vector<TreeNode *> ret;
if(s>e){
ret.push_back(NULL);
return ret;
}
for(int i = s;i<=e;i++){
vector<TreeNode *> left = generate(s,i-1);
vector<TreeNode*> right = generate(i+1,e);
for(int j = 0;j<left.size();j++){
for(int k = 0;k<right.size();k++){
TreeNode * node = new TreeNode(i+1);//数字i为root
ret.push_back(node);
node->left = left[j];
node->right = right[k];
}
}
}
return ret;//返回s-e形成的所有树
}
vector<TreeNode *> generateTrees(int n) {
return generate(0,n-1);
}
2、Interleaving String
vector<TreeNode *> generate(int s,int e){
vector<TreeNode *> ret;
if(s>e){
ret.push_back(NULL);
return ret;
}
for(int i = s;i<=e;i++){
vector<TreeNode *> left = generate(s,i-1);
vector<TreeNode*> right = generate(i+1,e);
for(int j = 0;j<left.size();j++){
for(int k = 0;k<right.size();k++){
TreeNode * node = new TreeNode(i+1);//数字i为root
ret.push_back(node);
node->left = left[j];
node->right = right[k];
}
}
}
return ret;//返回s-e形成的所有树
}
vector<TreeNode *> generateTrees(int n) {
return generate(0,n-1);
}
Given s1, s2, s3, find whether s3 is formed by the interleaving of s1 and s2.
For example,
Given:
s1 = "aabcc"
,
s2 = "dbbca"
,
When s3 = "aadbbcbcac"
, return true.
When s3 = "aadbbbaccc"
, return false.
m个s1和n个s2可以组成m+n个s3的前缀
A[m][n] = A[m-1][n](s1[m]==s3[m+n])||A[m][n-1](s2[n]==s3[m+n])
这个动态公式自己是当时想出来,现在整理有些忘了,额。。。
bool isInterleave(string s1, string s2, string s3) {
if(s1.size()+s2.size()!=s3.size()){
return false;
}
vector<vector<bool>> vec;
for(int i = 0;i<=s1.size();i++){
vector<bool> tmp(s2.size()+1);
for(int j = 1;j<=s2.size();j++){
tmp[j] = false;
}
vec.push_back(tmp);
}
vec[0][0]= true;
for(int i = 1; i <= s1.size(); i++)
vec[i][0] = vec[i-1][0] && (s3[i-1] == s1[i-1]);
for(int j = 1; j <= s2.size(); j++)
vec[0][j] = vec[0][j-1] && (s3[j-1] == s2[j-1]);
for(int i = 1;i<=s1.size();i++)
for(int j = 1;j<=s2.size();j++)
vec[i][j] =(s1[i-1]==s3[i+j-1]&&vec[i-1][j])||(s2[j-1]==s3[i+j-1]&&vec[i][j-1]);
return vec[s1.size()][s2.size()];
}
bool isInterleave(string s1, string s2, string s3) {
if(s1.size()+s2.size()!=s3.size()){
return false;
}
vector<vector<bool>> vec;
for(int i = 0;i<=s1.size();i++){
vector<bool> tmp(s2.size()+1);
for(int j = 1;j<=s2.size();j++){
tmp[j] = false;
}
vec.push_back(tmp);
}
vec[0][0]= true;
for(int i = 1; i <= s1.size(); i++)
vec[i][0] = vec[i-1][0] && (s3[i-1] == s1[i-1]);
for(int j = 1; j <= s2.size(); j++)
vec[0][j] = vec[0][j-1] && (s3[j-1] == s2[j-1]);
for(int i = 1;i<=s1.size();i++)
for(int j = 1;j<=s2.size();j++)
vec[i][j] =(s1[i-1]==s3[i+j-1]&&vec[i-1][j])||(s2[j-1]==s3[i+j-1]&&vec[i][j-1]);
return vec[s1.size()][s2.size()];
}
3、Validate Binary Search Tree && Recover Binary Search Tree
把这两个问题放在一块,一个是检测是否正确的tree,一个是BST有两个结点交换了,修复。
Given a binary tree, determine if it is a valid binary search tree (BST).
Assume a BST is defined as follows:
- The left subtree of a node contains only nodes with keys less than the node's key.
- The right subtree of a node contains only nodes with keys greater than the node's key.
- Both the left and right subtrees must also be binary search trees.
依然是递归方式,不过将中间结果进行存储,判断一个二叉查找数的正确与否,中序遍历就可以了。
class Solution {
public:
TreeNode * pre;
bool result;
bool isValidBST(TreeNode *root) {
pre = NULL;
result = true;
inorder(root);
return result;
}
void inorder(TreeNode * root){
if(!result){
return;
}
if(NULL==root){
return;
}
inorder(root->left);
if(pre!=NULL&&pre->val>=root->val){//递减排序,前一个不可能大于等于第二个
result = false;
}
pre = root;
inorder(root->right);
}
};
class Solution {
public:
TreeNode * pre;
bool result;
bool isValidBST(TreeNode *root) {
pre = NULL;
result = true;
inorder(root);
return result;
}
void inorder(TreeNode * root){
if(!result){
return;
}
if(NULL==root){
return;
}
inorder(root->left);
if(pre!=NULL&&pre->val>=root->val){//递减排序,前一个不可能大于等于第二个
result = false;
}
pre = root;
inorder(root->right);
}
};
Two elements of a binary search tree (BST) are swapped by mistake.
Recover the tree without changing its structure.
Note:A solution using O(n) space is pretty straight forward. Could you devise a constant space solution?
BST中两个结点交换了,进行修复,不能改变结构。两个指针进行保存出错的两个指针,这里需要考虑的是,这两个指针可能就是root和left child,所以如果第一次记录的时候,需要将违反规定的两个数据进行同时保存,后期如果遇到其他的错误,则将第二个指针进行覆盖。
依然是中序遍历。。。这个是参考别人的,虽然现在可以理解,但是却根本无法想到这条道路上去。todo
class Solution {
public:
TreeNode * pre,*s1,*s2;
void recoverTree(TreeNode *root) {
pre = s1 = s2 = NULL;
inorder_find(root);
swap(s1->val,s2->val);
}
void inorder_find(TreeNode * root){
if(NULL == root){
return;
}
inorder_find(root->left);
if(pre!=NULL&&pre->val>root->val){
if(s1 == NULL){
s1 = pre;
s2 = root;
}
else{
s2 = root;
}
}
pre = root;
inorder_find(root->right);
}
};
class Solution {
public:
TreeNode * pre,*s1,*s2;
void recoverTree(TreeNode *root) {
pre = s1 = s2 = NULL;
inorder_find(root);
swap(s1->val,s2->val);
}
void inorder_find(TreeNode * root){
if(NULL == root){
return;
}
inorder_find(root->left);
if(pre!=NULL&&pre->val>root->val){
if(s1 == NULL){
s1 = pre;
s2 = root;
}
else{
s2 = root;
}
}
pre = root;
inorder_find(root->right);
}
};
4、Restore IP Addresses
Given a string containing only digits, restore it by returning all possible valid IP address combinations.
For example:
Given "25525511135"
,
return ["255.255.11.135", "255.255.111.35"]
. (Order does not matter)
自己的方法,比较繁琐,如果真要写的话,需要考虑很多情况。好长,不过也不怎么想解释了,其实就是建立三个循环,但是考虑某些位置上是0,或者不能通过的情况
class Solution {
public:
/**
j建立三个大循环,然后相当于分割成4份
但是这种方法不好,调试也是一会,如果是面试题,肯定会悲剧的
**/
vector<string> restoreIpAddresses(string s) {
vector<string> ret;
if(s.size()>12||s.size()<4){
return ret;
}
string dot = ".";
int len = s.size();
for(int i=0;i<3;i++){
string tmp = "";
if(s[0]=='0'&&i==0){
tmp = '0';
}
else{
if(s[0]=='0'){
break;
}
tmp = s.substr(0,i+1);
if(!GetData(tmp)){
continue;
}
}
for(int j=i+1;j<=i+3&j<=len-3;j++){
if(s[i+1]=='0'&&j==i+1){
tmp.push_back('.');
tmp.push_back('0');
}
else{
if(s[i+1]=='0'){
break;
}
if(!GetData(s.substr(i+1,j-i))){
continue;
}
tmp.append(".");
tmp.append(s.substr(i+1,j-i));
}
for(int k = j+1;k<=len-2&&k<=j+3;k++){
if(s[j+1]=='0'&&k==j+1){
tmp.push_back('.');
tmp.push_back('0');
}
else{
if(s[j+1]=='0'){
break;
}
if(!GetData(s.substr(j+1,k-j))){
continue;
}
tmp.append(".");
tmp.append(s.substr(j+1,k-j));
}
if(s[k+1]=='0'){
if(k+1 == len-1){
tmp.push_back('.');
tmp.push_back('0');
ret.push_back(tmp);
while(tmp.back()!='.'){
tmp.pop_back();
}
tmp.pop_back();
}
while(tmp.back()!='.'){
tmp.pop_back();
}
tmp.pop_back();
continue;
}
if(!GetData(s.substr(k+1,len-k))){
while(tmp.back()!='.'){
tmp.pop_back();
}
tmp.pop_back();
continue;
}
tmp.append(".");
tmp.append(s.substr(k+1,len-k));
ret.push_back(tmp);
while(tmp.back()!='.'){
tmp.pop_back();
}
tmp.pop_back();
while(tmp.back()!='.'){
tmp.pop_back();
}
tmp.pop_back();
}
while(tmp.back()!='.'){
tmp.pop_back();
}
tmp.pop_back();
}
}
return ret;
}
bool GetData(string s){
int sum = 0;
for(int i = 0;i<s.size();i++){
sum = sum*10+(s[i]-'0');
}
if(sum>0&&sum<=255){
return true;
}
else
return false;
}
};
第二种方法,很容易懂了。。DFS的方法,
class Solution {
public:
/**
j建立三个大循环,然后相当于分割成4份
但是这种方法不好,调试也是一会,如果是面试题,肯定会悲剧的
**/
vector<string> restoreIpAddresses(string s) {
vector<string> ret;
if(s.size()>12||s.size()<4){
return ret;
}
string dot = ".";
int len = s.size();
for(int i=0;i<3;i++){
string tmp = "";
if(s[0]=='0'&&i==0){
tmp = '0';
}
else{
if(s[0]=='0'){
break;
}
tmp = s.substr(0,i+1);
if(!GetData(tmp)){
continue;
}
}
for(int j=i+1;j<=i+3&j<=len-3;j++){
if(s[i+1]=='0'&&j==i+1){
tmp.push_back('.');
tmp.push_back('0');
}
else{
if(s[i+1]=='0'){
break;
}
if(!GetData(s.substr(i+1,j-i))){
continue;
}
tmp.append(".");
tmp.append(s.substr(i+1,j-i));
}
for(int k = j+1;k<=len-2&&k<=j+3;k++){
if(s[j+1]=='0'&&k==j+1){
tmp.push_back('.');
tmp.push_back('0');
}
else{
if(s[j+1]=='0'){
break;
}
if(!GetData(s.substr(j+1,k-j))){
continue;
}
tmp.append(".");
tmp.append(s.substr(j+1,k-j));
}
if(s[k+1]=='0'){
if(k+1 == len-1){
tmp.push_back('.');
tmp.push_back('0');
ret.push_back(tmp);
while(tmp.back()!='.'){
tmp.pop_back();
}
tmp.pop_back();
}
while(tmp.back()!='.'){
tmp.pop_back();
}
tmp.pop_back();
continue;
}
if(!GetData(s.substr(k+1,len-k))){
while(tmp.back()!='.'){
tmp.pop_back();
}
tmp.pop_back();
continue;
}
tmp.append(".");
tmp.append(s.substr(k+1,len-k));
ret.push_back(tmp);
while(tmp.back()!='.'){
tmp.pop_back();
}
tmp.pop_back();
while(tmp.back()!='.'){
tmp.pop_back();
}
tmp.pop_back();
}
while(tmp.back()!='.'){
tmp.pop_back();
}
tmp.pop_back();
}
}
return ret;
}
bool GetData(string s){
int sum = 0;
for(int i = 0;i<s.size();i++){
sum = sum*10+(s[i]-'0');
}
if(sum>0&&sum<=255){
return true;
}
else
return false;
}
};
class Solution {
private:
vector<string> ret;
int pos[4];
public:
bool check(string &s, int beg, int end)
{
string ip(s, beg, end - beg + 1);
if (ip.size() == 1)
return "0" <= ip && ip <= "9";
else if (ip.size() == 2)
return "10" <= ip && ip <= "99";
else if (ip.size() == 3)
return "100" <= ip && ip <= "255";
else
return false;
}
void dfs(int dep, int maxDep, string &s, int start)
{
if (dep == maxDep)
{
if (start == s.size())
{
int beg = 0;
string addr;
for(int i = 0; i < maxDep; i++)
{
string ip(s, beg, pos[i] - beg + 1);
beg = pos[i] + 1;
addr += i == 0 ? ip : "." + ip;
}
ret.push_back(addr);
}
return;
}
for(int i = start; i < s.size(); i++)
if (check(s, start, i))
{
pos[dep] = i;
dfs(dep + 1, maxDep, s, i + 1);
}
}
vector<string> restoreIpAddresses(string s) {
// Start typing your C/C++ solution below
// DO NOT write int main() function
ret.clear();
dfs(0, 4, s, 0);
return ret;
}
};
class Solution {
private:
vector<string> ret;
int pos[4];
public:
bool check(string &s, int beg, int end)
{
string ip(s, beg, end - beg + 1);
if (ip.size() == 1)
return "0" <= ip && ip <= "9";
else if (ip.size() == 2)
return "10" <= ip && ip <= "99";
else if (ip.size() == 3)
return "100" <= ip && ip <= "255";
else
return false;
}
void dfs(int dep, int maxDep, string &s, int start)
{
if (dep == maxDep)
{
if (start == s.size())
{
int beg = 0;
string addr;
for(int i = 0; i < maxDep; i++)
{
string ip(s, beg, pos[i] - beg + 1);
beg = pos[i] + 1;
addr += i == 0 ? ip : "." + ip;
}
ret.push_back(addr);
}
return;
}
for(int i = start; i < s.size(); i++)
if (check(s, start, i))
{
pos[dep] = i;
dfs(dep + 1, maxDep, s, i + 1);
}
}
vector<string> restoreIpAddresses(string s) {
// Start typing your C/C++ solution below
// DO NOT write int main() function
ret.clear();
dfs(0, 4, s, 0);
return ret;
}
};
5、Reverse Linked List II &&
Rotate List
Reverse a linked list from position m to n. Do it in-place and in one-pass.
For example:
Given 1->2->3->4->5->NULL
, m = 2 and n = 4,
return 1->4->3->2->5->NULL
.
Note:
Given m, n satisfy the following condition:
1 ≤ m ≤ n ≤ length of list.
将m-n之间的反转,然后记住反转之前的pre和end,然后指向就可以了,需要考虑m=1
class Solution {
public:
ListNode *reverseBetween(ListNode *head, int m, int n) {
if(m==n){
return head;
}
int i = 0;
ListNode * begin = head;
ListNode * end = head;
ListNode * beginpre = head;
while(i<n-m){
end = end->next;
i++;
}
i = 1;
while(i<m){
beginpre = begin;
begin = begin->next;
end = end->next;
i++;
}
ListNode * endnext = end->next;
reverse(begin,end);
if(begin == head){
begin->next = endnext;
return end;
}
else{
begin->next = endnext;
beginpre->next = end;
return head;
}
}
void reverse(ListNode * begin,ListNode * end){
if(begin == end){
return;
}
ListNode * cur = begin;
ListNode * curnext = begin->next;
ListNode * p = curnext;
while(curnext!=end){
p=p->next;
curnext->next = cur;
cur = curnext;
curnext = p;
}
end->next = cur;
}
};
class Solution {
public:
ListNode *reverseBetween(ListNode *head, int m, int n) {
if(m==n){
return head;
}
int i = 0;
ListNode * begin = head;
ListNode * end = head;
ListNode * beginpre = head;
while(i<n-m){
end = end->next;
i++;
}
i = 1;
while(i<m){
beginpre = begin;
begin = begin->next;
end = end->next;
i++;
}
ListNode * endnext = end->next;
reverse(begin,end);
if(begin == head){
begin->next = endnext;
return end;
}
else{
begin->next = endnext;
beginpre->next = end;
return head;
}
}
void reverse(ListNode * begin,ListNode * end){
if(begin == end){
return;
}
ListNode * cur = begin;
ListNode * curnext = begin->next;
ListNode * p = curnext;
while(curnext!=end){
p=p->next;
curnext->next = cur;
cur = curnext;
curnext = p;
}
end->next = cur;
}
};
Given a list, rotate the list to the right by k places, where k is non-negative.
For example:
Given 1->2->3->4->5->NULL
and k = 2
,
return 4->5->1->2->3->NULL
.
和上面类似
class Solution {
public:
/*
遗忘的情况
1.只有一个元素的时候
2.K是链表的倍数的时候
*/
ListNode *rotateRight(ListNode *head, int k) {
if(head==NULL||k<=0){
return head;
}
ListNode * tmphead = head;
int len = 0;
ListNode * p = head;
while(p!=NULL){
len++;
p = p->next;
}
if(len == 1){
return head;
}
k = k%len;//len是长度
if(k == 0){
return head;
}
k = len-k;
p = head;
while(--k>0){
p = p->next;
}
head = p->next;
p->next = NULL;
p = head;
while(p->next!=NULL){
p = p->next;
}
p->next = tmphead;
return head;
}
};
以上大多是和链表有关的,下面的一些就是和数的操作有关了,排序,变换。
Given a list, rotate the list to the right by k places, where k is non-negative.
For example:
Given 1->2->3->4->5->NULL
and k = 2
,
return 4->5->1->2->3->NULL
.
class Solution {
public:
/*
遗忘的情况
1.只有一个元素的时候
2.K是链表的倍数的时候
*/
ListNode *rotateRight(ListNode *head, int k) {
if(head==NULL||k<=0){
return head;
}
ListNode * tmphead = head;
int len = 0;
ListNode * p = head;
while(p!=NULL){
len++;
p = p->next;
}
if(len == 1){
return head;
}
k = k%len;//len是长度
if(k == 0){
return head;
}
k = len-k;
p = head;
while(--k>0){
p = p->next;
}
head = p->next;
p->next = NULL;
p = head;
while(p->next!=NULL){
p = p->next;
}
p->next = tmphead;
return head;
}
};
class Solution {
public:
/*
遗忘的情况
1.只有一个元素的时候
2.K是链表的倍数的时候
*/
ListNode *rotateRight(ListNode *head, int k) {
if(head==NULL||k<=0){
return head;
}
ListNode * tmphead = head;
int len = 0;
ListNode * p = head;
while(p!=NULL){
len++;
p = p->next;
}
if(len == 1){
return head;
}
k = k%len;//len是长度
if(k == 0){
return head;
}
k = len-k;
p = head;
while(--k>0){
p = p->next;
}
head = p->next;
p->next = NULL;
p = head;
while(p->next!=NULL){
p = p->next;
}
p->next = tmphead;
return head;
}
};
以上大多是和链表有关的,下面的一些就是和数的操作有关了,排序,变换。
Given a set of distinct integers, S, return all possible subsets.
Note:
- Elements in a subset must be in non-descending order.
- The solution set must not contain duplicate subsets.
For example,
If S = [1,2,3]
, a solution is:
[ [3], [1], [2], [1,2,3], [1,3], [2,3], [1,2], [] ]题目要求,不能包含重复的子集,而且是不能是降序的。
这个相对于第二题,有一个容易的地方,就是候选集是distinct的,所以递归进行添加数据就可以了。
这里的vector是传值进去的哦,不是引用,这样也就不用再费劲把元素push进去,然后pop出来。
class Solution {
public:
vector<vector<int> > ret;
int len;
vector<vector<int> > subsets(vector<int> &S) {
len = S.size();
if(len == 0){
return ret;
}
sort(S.begin(),S.end());
vector<int> tmp;
addinvec(0,tmp,S);
return ret;
}
void addinvec(int index,vector<int> tmp,vector<int> &S){
if(index==len-1){
ret.push_back(tmp);
tmp.push_back(S[index]);
ret.push_back(tmp);
return;
}
addinvec(index+1,tmp,S);
tmp.push_back(S[index]);
addinvec(index+1,tmp,S);
}
};
第二题,允许存在相同的元素,但是不允许相同的子集出现。
class Solution {
public:
vector<vector<int> > ret;
int len;
vector<vector<int> > subsets(vector<int> &S) {
len = S.size();
if(len == 0){
return ret;
}
sort(S.begin(),S.end());
vector<int> tmp;
addinvec(0,tmp,S);
return ret;
}
void addinvec(int index,vector<int> tmp,vector<int> &S){
if(index==len-1){
ret.push_back(tmp);
tmp.push_back(S[index]);
ret.push_back(tmp);
return;
}
addinvec(index+1,tmp,S);
tmp.push_back(S[index]);
addinvec(index+1,tmp,S);
}
};
这里利用了一个非常巧妙的办法,这里利用的是将interger作为一个 个体 参加,比如说,2,2,这两个数据,作为一个元素。1,这样distinct的数也是作为一个数据。
这样在递归的时候就可以控制数量了。
vector<vector<int> > ret;
vector<vector<int> > subsetsWithDup(vector<int> &S) {
sort(S.begin(),S.end());
vector<int> tmp;
Insert(tmp,0,S);
return ret;
}
void Insert(vector<int> tmp,int begin,vector<int> &S){
if(begin>=S.size()){
ret.push_back(tmp);
return;
}
int cur = S[begin];
int next = begin;
while(next<S.size()&&S[next]==cur){
next++;
}
Insert(tmp,next,S);
for(int i = begin;i<next;i++){
tmp.push_back(S[i]);
Insert(tmp,next,S);
}
}
7、Decode Ways
vector<vector<int> > ret;
vector<vector<int> > subsetsWithDup(vector<int> &S) {
sort(S.begin(),S.end());
vector<int> tmp;
Insert(tmp,0,S);
return ret;
}
void Insert(vector<int> tmp,int begin,vector<int> &S){
if(begin>=S.size()){
ret.push_back(tmp);
return;
}
int cur = S[begin];
int next = begin;
while(next<S.size()&&S[next]==cur){
next++;
}
Insert(tmp,next,S);
for(int i = begin;i<next;i++){
tmp.push_back(S[i]);
Insert(tmp,next,S);
}
}
A message containing letters from A-Z
is being encoded to numbers using the following mapping:
'A' -> 1 'B' -> 2 ... 'Z' -> 26
Given an encoded message containing digits, determine the total number of ways to decode it.
For example,
Given encoded message "12"
, it could be decoded as "AB"
(1 2) or "L"
(12).
The number of ways decoding "12"
is 2.
需要考虑是,按1个和2个元素作为操作单元,考虑0元素。是不是和青蛙跳的那个题目相似,跳一次台阶,跳两次台阶。
定义数组number,number[i]意味着:字符串s[0..i-1]可以有number[i]种解码方法。
回想爬楼梯问题一样,number[i] = number[i-1] + number[i-2]
但不同的是本题有多种限制:
第一: s[i-1]不能是0,如果s[i-1]是0的话,number[i]就只能等于number[i-2]
第二,s[i-2,i-1]中的第一个字符不能是0,而且Integer.parseInt(s.substring(i-2,i))获得的整数必须在0到26之间。
int numDecodings(string s) {
int len = s.size();
if(len==0||s[0]=='0'){
return 0;
}
vector<int> vec(len+1);
vec[0] = 1;
vec[1] = 1;
int tmp;
for(int i = 2;i<=len;i++){
if(s[i-1]!='0'){//这里可能有些疑惑的地方,这里的意思是,如果i-1不是0,则veci为vec i-1的值,如果不是,veci为0.
vec[i] = vec[i-1];
}
if(s[i-2]!='0'){
if(getchar(s.substr(i-2,2))){
vec[i]+=vec[i-2];//配合上面vec i的值,vec i = vec i(vec i-1 ) + vec i-2
}
}
}
return vec[len];
}
bool getchar(string s){//判断2位字符在1-26之间
if(s.size()>2||s[0]=='0'){
return false;
}
if((s.size()==1&&s[0]>'0'&&s[0]<='9')||(s.size()==2&&s>="10"&&s<="26")){
return true;
}
else{
return false;
}
}
8、Merge Sorted Array &&
int numDecodings(string s) {
int len = s.size();
if(len==0||s[0]=='0'){
return 0;
}
vector<int> vec(len+1);
vec[0] = 1;
vec[1] = 1;
int tmp;
for(int i = 2;i<=len;i++){
if(s[i-1]!='0'){//这里可能有些疑惑的地方,这里的意思是,如果i-1不是0,则veci为vec i-1的值,如果不是,veci为0.
vec[i] = vec[i-1];
}
if(s[i-2]!='0'){
if(getchar(s.substr(i-2,2))){
vec[i]+=vec[i-2];//配合上面vec i的值,vec i = vec i(vec i-1 ) + vec i-2
}
}
}
return vec[len];
}
bool getchar(string s){//判断2位字符在1-26之间
if(s.size()>2||s[0]=='0'){
return false;
}
if((s.size()==1&&s[0]>'0'&&s[0]<='9')||(s.size()==2&&s>="10"&&s<="26")){
return true;
}
else{
return false;
}
}
Merge Two Sorted Lists
Given two sorted integer arrays A and B, merge B into A as one sorted array.
Note:
You may assume that A has enough space (size that is greater or equal to m + n) to hold additional elements from B. The number of elements initialized in A and B are m and nrespectively.
void merge(int A[], int m, int B[], int n) {
int i=m-1,j=n-1;
int index = m+n-1;
while(i>=0&&j>=0){
if(A[i]>B[j]){
A[index--]=A[i];
i--;
}
else{
A[index--]=B[j];
j--;
}
}
while(j>=0&&index>=0){
A[index--]=B[j--];
}
}
list的合并,首先确定head,然后将数据依次比较大小添加进入合并list
ListNode *mergeTwoLists(ListNode *l1, ListNode *l2) {
if(l1 == NULL){
return l2;
}
if(l2 == NULL){
return l1;
}
ListNode * head = l1->val>l2->val?l2:l1;
ListNode * p = head;
ListNode * t1 = l1,*t2 = l2;
if(l1->val>l2->val){
t1 = l1;
t2 = l2->next;
}
else{
t1 = l1->next;
t2 = l2;
}
while(t1!=NULL&&t2!=NULL){
if(t1->val>t2->val){
p->next = t2;
p = p->next;
t2 = t2->next;
}else{
p->next = t1;
p = p->next;
t1 = t1->next;
}
}
while(t1!=NULL){
p->next = t1;
t1 = t1->next;
p = p->next;
}
while(t2!=NULL){
p->next = t2;
t2 = t2->next;
p = p->next;
}
p->next=NULL;
return head;
}
9、Gray Code
void merge(int A[], int m, int B[], int n) {
int i=m-1,j=n-1;
int index = m+n-1;
while(i>=0&&j>=0){
if(A[i]>B[j]){
A[index--]=A[i];
i--;
}
else{
A[index--]=B[j];
j--;
}
}
while(j>=0&&index>=0){
A[index--]=B[j--];
}
}
list的合并,首先确定head,然后将数据依次比较大小添加进入合并list
ListNode *mergeTwoLists(ListNode *l1, ListNode *l2) {
if(l1 == NULL){
return l2;
}
if(l2 == NULL){
return l1;
}
ListNode * head = l1->val>l2->val?l2:l1;
ListNode * p = head;
ListNode * t1 = l1,*t2 = l2;
if(l1->val>l2->val){
t1 = l1;
t2 = l2->next;
}
else{
t1 = l1->next;
t2 = l2;
}
while(t1!=NULL&&t2!=NULL){
if(t1->val>t2->val){
p->next = t2;
p = p->next;
t2 = t2->next;
}else{
p->next = t1;
p = p->next;
t1 = t1->next;
}
}
while(t1!=NULL){
p->next = t1;
t1 = t1->next;
p = p->next;
}
while(t2!=NULL){
p->next = t2;
t2 = t2->next;
p = p->next;
}
p->next=NULL;
return head;
}
ListNode *mergeTwoLists(ListNode *l1, ListNode *l2) {
if(l1 == NULL){
return l2;
}
if(l2 == NULL){
return l1;
}
ListNode * head = l1->val>l2->val?l2:l1;
ListNode * p = head;
ListNode * t1 = l1,*t2 = l2;
if(l1->val>l2->val){
t1 = l1;
t2 = l2->next;
}
else{
t1 = l1->next;
t2 = l2;
}
while(t1!=NULL&&t2!=NULL){
if(t1->val>t2->val){
p->next = t2;
p = p->next;
t2 = t2->next;
}else{
p->next = t1;
p = p->next;
t1 = t1->next;
}
}
while(t1!=NULL){
p->next = t1;
t1 = t1->next;
p = p->next;
}
while(t2!=NULL){
p->next = t2;
t2 = t2->next;
p = p->next;
}
p->next=NULL;
return head;
}
The gray code is a binary numeral system where two successive values differ in only one bit.
Given a non-negative integer n representing the total number of bits in the code, print the sequence of gray code. A gray code sequence must begin with 0.
For example, given n = 2, return [0,1,3,2]
. Its gray code sequence is:
00 - 0 01 - 1 11 - 3 10 - 2
Note:
For a given n, a gray code sequence is not uniquely defined.
For example, [0,2,3,1]
is also a valid gray code sequence according to the above definition.
For now, the judge is able to judge based on one instance of gray code sequence. Sorry about that.
维基百科上定义是格雷码,题意是,给一个bit的数量,然后从00000...开始,每一次只有一位不同。这个是有数学规律的,自己一开始想到的是暴力的方法,但是这个其实可以用数学归纳出来的。
从第0个开始,第i个gray code为:(i>>1)^i(G(N) = (B(n)/2) XOR B(n),维基百科给出的公式。。。)
vector<int> grayCode(int n) {
// Start typing your C/C++ solution below
// DO NOT write int main() function
vector<int> res;
int num = 1<<n;
int i = 0;
while(i<num)
res.push_back((i>>1)^(i++));
return res;
}
vector<int> grayCode(int n) {
// Start typing your C/C++ solution below
// DO NOT write int main() function
vector<int> res;
int num = 1<<n;
int i = 0;
while(i<num)
res.push_back((i>>1)^(i++));
return res;
}
10、Scramble String
Given a string s1, we may represent it as a binary tree by partitioning it to two non-empty substrings recursively.
Below is one possible representation of s1 = "great"
:
great / \ gr eat / \ / \ g r e at / \ a t
To scramble the string, we may choose any non-leaf node and swap its two children.
For example, if we choose the node "gr"
and swap its two children, it produces a scrambled string "rgeat"
.
rgeat / \ rg eat / \ / \ r g e at / \ a t
We say that "rgeat"
is a scrambled string of "great"
.
Similarly, if we continue to swap the children of nodes "eat"
and "at"
, it produces a scrambled string "rgtae"
.
rgtae / \ rg tae / \ / \ r g ta e / \ t a
We say that "rgtae"
is a scrambled string of "great"
.
Given two strings s1 and s2 of the same length, determine if s2 is a scrambled string of s1.
判断一个字符串是否是另外一个字符串在树中表示反转的结果。现在没有了思路,不知道当时是怎么想的,应该也是参考别人的,当时对动态规划不是怎么熟悉,竟然是动态规划。。。
考虑两个字符串ab组成的s,s = ab|ba。
所以s是由ab组合而成,也可以是由ba组合而成。而字符串a也可以是由a1和a2或者a2和a1拼接而成。
class Solution {
public:
/*
减少重复计算的方法就是动态规划。动态规划是一种神奇的算法技术,不亲自去写,是很难完全掌握动态规划的。
这里我使用了一个三维数组boolean result[len][len][len],其中第一维为子串的长度,第二维为s1的起始索引,第三维为s2的起始索引。
result[k][i][j]表示s1[i...i+k]是否可以由s2[j...j+k]变化得来。
*/
bool isScramble(string s1, string s2) {
int len = s1.length();
if(len != s2.length()){
return false;
}
if(len == 0){
return true;
}
bool ***rev;
rev = new bool**[len];
for(int i = 0;i<len;i++){
rev[i] = new bool*[len];
for(int j = 0;j<len;j++){
rev[i][j] = new bool[len];
for(int k = 0;k<len;k++){
rev[i][j][k] = false;
}
}
}
for(int i = 0;i<len;i++){
for(int j = 0;j<len;j++){
rev[0][i][j] = (s1[i]==s2[j]);
}
}
for(int k = 2;k<=len;k++){//k是字符串长度
for(int i = len-k;i>=0;i--){//第一个字符的起始位置
for(int j = len-k;j>=0;j--){//第二个字符的起始位置
bool r = false;
for(int m = 1;m<k&&!r;m++){
r = (rev[m-1][i][j]&&rev[k-m-1][i+m][j+m])||(rev[m-1][i][j+k-m]&&rev[k-m-1][i+m][j]);
}
rev[k-1][i][j] = r;
}
}
}
bool ret = rev[len-1][0][0];
//销毁
for(int i = 0;i<len;i++){
for(int j = 0;j<len;j++){
delete[] rev[i][j];
}
delete[] rev[i];
}
return ret;
delete[] rev;
}
};
class Solution {
public:
/*
减少重复计算的方法就是动态规划。动态规划是一种神奇的算法技术,不亲自去写,是很难完全掌握动态规划的。
这里我使用了一个三维数组boolean result[len][len][len],其中第一维为子串的长度,第二维为s1的起始索引,第三维为s2的起始索引。
result[k][i][j]表示s1[i...i+k]是否可以由s2[j...j+k]变化得来。
*/
bool isScramble(string s1, string s2) {
int len = s1.length();
if(len != s2.length()){
return false;
}
if(len == 0){
return true;
}
bool ***rev;
rev = new bool**[len];
for(int i = 0;i<len;i++){
rev[i] = new bool*[len];
for(int j = 0;j<len;j++){
rev[i][j] = new bool[len];
for(int k = 0;k<len;k++){
rev[i][j][k] = false;
}
}
}
for(int i = 0;i<len;i++){
for(int j = 0;j<len;j++){
rev[0][i][j] = (s1[i]==s2[j]);
}
}
for(int k = 2;k<=len;k++){//k是字符串长度
for(int i = len-k;i>=0;i--){//第一个字符的起始位置
for(int j = len-k;j>=0;j--){//第二个字符的起始位置
bool r = false;
for(int m = 1;m<k&&!r;m++){
r = (rev[m-1][i][j]&&rev[k-m-1][i+m][j+m])||(rev[m-1][i][j+k-m]&&rev[k-m-1][i+m][j]);
}
rev[k-1][i][j] = r;
}
}
}
bool ret = rev[len-1][0][0];
//销毁
for(int i = 0;i<len;i++){
for(int j = 0;j<len;j++){
delete[] rev[i][j];
}
delete[] rev[i];
}
return ret;
delete[] rev;
}
};