日练三题,冰冻三尺非一日之寒。
今日题目:
1、划分链表; | tag:链表、两指针
2、唯一路径II; |tag:数组、DP
3、电话号码组合。 |tag:字符串、回溯
4、二叉树ZigZag层次遍历 | tag:树、BFS、栈
今日摘录:
你不愿意种花,你说,我不愿看见它一点点凋落。是的,为了避免结束,你避免了一切开始。
《避免》
86. Partition List | Difficulty: Medium
Given a linked list and a value x, partition it such that all nodes less than x come before nodes greater than or equal to x.
You should preserve the original relative order of the nodes in each of the two partitions.
For example,
Given 1->4->3->2->5->2 and x = 3,
return 1->2->2->4->3->5.
tag:链表、两个指针
题意:将链表中小于value的元素放到前面,大于等于value的元素放在后面并保持原来的顺序。
思路:
1、开始以为是快排的partition,后面发现不是那个意思。通俗理解为按照 x < value 将一部分元素筛选出来,并且保持剩下元素相对位置不变,然后将挑选出来的最后元素和剩下元素的第一个元素连起来。形成我们最终需要的最终链表。我的思路是创建两个指针分别存小的元素和大的元素,最后再拼接。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* partition(ListNode* head, int x) {
ListNode*cur=head,*next=NULL;
ListNode *smallHead = new ListNode (INT_MIN);
ListNode *small = smallHead;
ListNode *largeHead = new ListNode (INT_MIN);
ListNode *large = largeHead;
while(cur)
{
next = cur->next;
if(cur->val<x)
{
small->next = cur;
small = small->next;
small->next = NULL;
cur = next;
}
else
{
large->next = cur;
large = large->next;
large->next = NULL;
cur = next;
}
}
small->next = largeHead->next;
return smallHead->next;
}
};
结果:8ms
2、发现一个同样的思路,我怎么就写得这么丑,于是仿照别人自己重新写了一遍,终于好看多了。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* partition(ListNode* head, int x) {
ListNode node1(0),node2(0);
ListNode *p1 = &node1,*p2 = &node2;
while(head)
{
if(head->val<x)
{
p1->next = head;
p1 = p1->next;
}
else
{
p2 ->next = head;
p2 = p2->next;
}
head = head->next;
}
p1->next = node2.next;
p2->next = NULL;
return node1.next;
}
};
结果:8ms
update:2016.9.15:第二次刷代码
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* partition(ListNode* head, int x) {
ListNode *lessHead = new ListNode(INT_MIN),*greatHead = new ListNode(INT_MIN);
ListNode *less = lessHead,*great = greatHead;
ListNode*node = head;
while(node)
{
if(node->val < x) {less->next = node;less = less->next;}
else {great->next = node;great = great->next;}
node = node->next;
}
less->next = greatHead->next;
great->next = NULL;
return lessHead->next;
}
};
结果:9ms
63. Unique Paths II | Difficulty: Medium
Follow up for “Unique Paths”:
Now consider if some obstacles are added to the grids. How many unique paths would there be?
An obstacle and empty space is marked as 1 and 0 respectively in the grid.
For example,
There is one obstacle in the middle of a 3x3 grid as illustrated below.
[
[0,0,0],
[0,1,0],
[0,0,0]
]
The total number of unique paths is 2.
Note: m and n will be at most 100.
tag: 数组|DP
相关题目:Unique Path
题意:与那道求唯一路径数的题目非常类似,唯一的区别在于其中增加了一些障碍点,这些障碍点是走不通的。
思路:
1、与当时在求唯一路径数的时候情况很类似,是首先将第0行和第0列初始化为1,因为这边只有一种情况的存在,然后从第1行第1列的元素开始计算,每个值都是它左边的dp值和上面的dp值之和。
那么这里的区别在什么地方呢?在求dp[i][j]的时候,需要判断obstacleGrid[i][j]的值,也就是求到一个点的路径数,需要预先判断一下这个点能不能走,能走才加其左和上。
先用mn的时间复杂度和空间复杂度做一遍。
class Solution {
public:
int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {
int rows = obstacleGrid.size(),cols = obstacleGrid[0].size();
vector<vector<int>> dp(rows+1,vector<int>(cols+1,0));
dp[1][0] = 1;
for(int i=1;i<=rows;i++)
{
for(int j=1;j<=cols;j++)
{
if(!obstacleGrid[i-1][j-1]) dp[i][j]+=dp[i-1][j]+dp[i][j-1];
}
}
return dp[rows][cols];
}
};
结果:4ms
2、很类似unique path题,这里也能优化空间到o(min(m,n)),这里懒得设置新的接口,所以就任选m或者n来实现。
class Solution {
public:
int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {
int rows = obstacleGrid.size(),cols = obstacleGrid[0].size();
vector<int> dp(rows,0);
for(int i=0;i<rows;i++)
{
if(!obstacleGrid[i][0]) dp[i]=1;
else break;
}
for(int i=1;i<cols;i++)
{
if(dp[0] && !obstacleGrid[0][i]) dp[0]=1;
else dp[0]=0;
for(int j=1;j<rows;j++)
{
if(!obstacleGrid[j][i])
{
dp[j]+=dp[j-1];
}
else dp[j]=0;
}
}
return dp[rows-1];
}
};
结果:4ms
class Solution {
public:
int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {
int rows = obstacleGrid.size(),cols = obstacleGrid[0].size();
vector<int> dp(rows,0);
for(int i=0;i<rows;i++)
{
if(!obstacleGrid[i][0]) dp[i]=1;
else break;
}
for(int i=1;i<cols;i++)
{
bool flag = false;
if(dp[0] && !obstacleGrid[0][i]) {dp[0]=1;flag=true;}
else dp[0]=0;
for(int j=1;j<rows;j++)
{
if(!obstacleGrid[j][i])
{
dp[j]+=dp[j-1];
flag = true;
}
else dp[j]=0;
}
if(!flag) return 0;
}
return dp[rows-1];
}
};
结果:4ms
还可以在每次赋值的时候加一次条件判断,如果某一列全部都是0,那么就可以提前终止。
17. Letter Combinations of a Phone Number |Difficulty: Medium
Given a digit string, return all possible letter combinations that the number could represent.
A mapping of digit to letters (just like on the telephone buttons) is given below.
Input:Digit string “23”
Output: [“ad”, “ae”, “af”, “bd”, “be”, “bf”, “cd”, “ce”, “cf”].
tag:数组、回溯
题意:给一个电话号码,每个按键上面都对应几个字母,求所有可能的字母组合
思路:
1、直接模拟一下”23”这种情况下是如何生成结果的
首先访问2,这里有3种情况,a、b、c,对于每个字母,后面又进来一个3,这个时候对于a、b、c三种情况,每一种都对应了d、e、f三中情况,组合起来就
是9种情况。
class Solution {
public:
vector<string> letterCombinations(string digits) {
string charmap[10] = {"0", "1", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"};
vector<string>res;
if(digits.size()==0) return res;
res.push_back("");
int length = digits.size();
for(int i=0;i<length;i++)
{
vector<string> tmp;
string chars = charmap[digits[i] - '0'];
for(int c=0;c<chars.size();c++)
{
for(int j=0;j<res.size();j++)
tmp.push_back(res[j]+chars[c]);
}
res = tmp;
}
return res;
}
};
结果:0ms
输入:”36” 输出:[“dm”,”em”,”fm”,”dn”,”en”,”fn”,”do”,”eo”,”fo”]
2、如果希望输出格式类似回溯顺序,即aaa、aab、aac、aba、abb……等等,应该使用如下思路
class Solution {
public:
vector<string> letterCombinations(string digits) {
string charmap[10] = {"0", "1", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"};
vector<string>res;
if(digits.size()==0) return res;
res.push_back("");
int length = digits.size();
for(int i=0;i<length;i++)
{
while(res.front().size()==i)
{
string tmp = res.front();
res.erase(res.begin());
for (auto c : charmap[digits[i]-'0'])
{
res.push_back(tmp+c);
}
}
}
return res;
}
};
结果:0ms
输入:“36” 输出:[“dm”,”dn”,”do”,”em”,”en”,”eo”,”fm”,”fn”,”fo”]
103. Binary Tree Zigzag Level Order Traversal | Difficulty: Medium
Given a binary tree, return the zigzag level order traversal of its nodes’ values. (ie, from left to right, then right to left for the next level and alternate between).
For example:
Given binary tree [3,9,20,null,null,15,7],
3
/ \
9 20
/ \
15 7
return its zigzag level order traversal as:
[
[3],
[20,9],
[15,7]
]
tag:树、BFS、栈
题意:给一棵树,用zigzag层次遍历的方法去遍历这棵树。
思路:
1、很显然,用两个栈或者队列可以实现这个功能,这里以栈为例。每次访问一层,我们就在其中的一个栈中去访问元素,直到这层访问完毕就去访问剩下的那个栈。那么如何控制从左到右和从右到左之间的切换呢?这个时候可以设置一个标志位,每次换层的时候切换一下标志位就可以了。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
vector<vector<int>> zigzagLevelOrder(TreeNode* root) {
vector<vector<int> > res;
if(!root) return res;
stack<TreeNode*> nodes[2];
int flag = 0;
nodes[flag].push(root);
vector<int> level;
while(!nodes[flag].empty())
{
TreeNode* tmp = nodes[flag].top();
nodes[flag].pop();
level.push_back(tmp->val);
if(flag)
{
if(tmp->right) nodes[1-flag].push(tmp->right);
if(tmp->left) nodes[1-flag].push(tmp->left);
}
else
{
if(tmp->left) nodes[1-flag].push(tmp->left);
if(tmp->right) nodes[1-flag].push(tmp->right);
}
if(nodes[flag].empty())
{
res.push_back(level);
level.clear();
flag = 1-flag;
}
}
return res;
}
};
结果:4ms
2、可以再做一些优化,只用一个队列加上一个标志位
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
vector<vector<int>> zigzagLevelOrder(TreeNode* root) {
vector<vector<int> > res;
if(!root) return res;
queue<TreeNode*> nodes;
bool LeftToRight = true;
nodes.push(root);
while(!nodes.empty())
{
int size = nodes.size();
vector<int> level(size);
for(int i=0;i<size;i++)
{
TreeNode* tmp = nodes.front();
nodes.pop();
int index = (LeftToRight)?i:size-1-i;
level[index] = tmp->val;
if(tmp->left) nodes.push(tmp->left);
if(tmp->right) nodes.push(tmp->right);
}
LeftToRight = !LeftToRight;
res.push_back(level);
}
return res;
}
};
结果:6ms