剑指offer&LeetCode
LeetCode All in One 题目讲解汇总(持续更新中…)【要是来不及直接刷题解吧hhh】
https://www.cnblogs.com/grandyang/p/4606334.html
Leetcode 分类顺序表第二版(增加重点250题)
https://cspiration.com/leetcodeClassification#103
反转问题
从头到尾打印链表
[Leetcode] Implement Stack using Queues 用队列实现栈
https://segmentfault.com/a/1190000003808785
复杂度
时间 O(N) 空间 O(N)
思路
和Implement Queue using Stack类似,我们也可以用两个队列来模拟栈的操作。当push时,我们将数字offer进非空的队列就行了。当pop时,因为要拿的是队列最后一个数,我们先将它前面的数offer进另一个队列,然后单独拿出最后一个数,并且不再offer进另一个队列,这样,另一个队列就少了最后一个数,而我们也拿到了最后一个数,而本来的队列就变成空了,等待下次的pop操作来填满。top操作和pop一样,区别在于我们拿到最后一个数后,还要再把它offer进另一个队列中。
class MyStack {
Queue<Integer> queue1;
Queue<Integer> queue2;
int size;
public MyStack(){
this.queue1 = new LinkedList<Integer>();
this.queue2 = new LinkedList<Integer>();
this.size = 0;
}
// Push element x onto stack.
public void push(int x) {
if(queue1.isEmpty()){
queue2.offer(x);
} else {
queue1.offer(x);
}
size++;
}
// Removes the element on top of the stack.
public int pop() {
if(size == 0){
return -1;
}
int res = 0;
// 将前面的数都offer进另一个队列,然后拿出最后一个数
if(queue1.isEmpty()){
for(int i = 0; i < size - 1; i++){
queue1.offer(queue2.poll());
}
res = queue2.poll();
} else {
for(int i = 0; i < size - 1; i++){
queue2.offer(queue1.poll());
}
res = queue1.poll();
}
size--;
return res;
}
// Get the top element.
public int top() {
if(size == 0){
return -1;
}
// 先执行pop
int top = pop();
// 然后将pop出来的数再塞回队列就行了
if(queue1.isEmpty()){
queue2.offer(top);
} else {
queue1.offer(top);
}
// 注意size也要加1
size++;
return top;
}
// Return whether the stack is empty.
public boolean empty() {
return size == 0;
}
}
编辑距离及编辑距离算法
问题:找出字符串的编辑距离,即把一个字符串s1最少经过多少步操作变成编程字符串s2,操作有三种,添加一个字符,删除一个字符,修改一个字符
http://www.cnblogs.com/biyeymyhjob/archive/2012/09/28/2707343.html
显然可以有如下动态规划公式:
if i == 0 且 j == 0,edit(i, j) = 0
if i == 0 且 j > 0,edit(i, j) = j
if i > 0 且j == 0,edit(i, j) = i
if i ≥ 1 且 j ≥ 1 ,edit(i, j) == min{ edit(i-1, j) + 1, edit(i, j-1) + 1, edit(i-1, j-1) + f(i, j) },
当第一个字符串的第i个字符不等于第二个字符串的第j个字符时,f(i, j) = 1;否则,f(i, j) = 0。
LeetCode 222. 完全二叉树的节点个数
https://blog.youkuaiyun.com/sinat_15723179/article/details/80937378
题目描述:
给出一个完全二叉树,求出该树的节点个数。
说明:
完全二叉树的定义如下:在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层,则该层包含 1~ 2h 个节点。
示例:
输入:
1
/ \
2 3
/ \ /
4 5 6
输出: 6
思路:这个解题方法是来自于leetCode上一个解法。主要思想是计算出树的高度,然后统计出叶子节点的数目,然后利用公式 nodenums=2^(height-1)-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:
int getHeight(TreeNode *root)
{
int height = 1;
while(root->left != NULL)
{
height++;
root = root->left;}
return height;
}
int countNodes(TreeNode* root) {
if(root == NULL)
return 0;
int height = getHeight(root);
//利用变形的二分法来计算叶子节点的个数
int leafCnt=0;
int level=height-2;
TreeNode *cur=root;
while(level>=0)
{
TreeNode *temp=cur->left;
for(int i=0; i<level;++i)
temp=temp->right;//找到最后一个right
if(temp){//判断是否存在,如果存在这一层前半部分的叶子节点肯定是存在的,然后就可以从当前cur的右边看右边是否存在叶子节点
leafCnt+=1<<level;
cur=cur->right;
}
else
cur=cur->left;
level--;
}
if(cur)//是否存在最后一个单独的节点
leafCnt++;
return (1<<height-1)-1+leafCnt;//左移和右移运算符优先级很低,注意加括号
}
};
---------------------
作者:一个假程序媛
来源:优快云
原文:https://blog.csdn.net/sinat_15723179/article/details/80937378
版权声明:本文为博主原创文章,转载请附上博文链接!
[LeetCode] Implement Trie (Prefix Tree) 实现字典树(前缀树)
http://www.cnblogs.com/grandyang/p/4491665.html【强推点一点!这个博主好腻害!有很多】
题目描述
Implement a trie with insert, search, and startsWith methods.
Note:
You may assume that all inputs are consist of lowercase letters a-z.
解析:
这道题让我们实现一个重要但又有些复杂的数据结构-字典树, 又称前缀树或单词查找树,详细介绍可以参见网友董的博客,例如,一个保存了8个键的trie结构,“A”, “to”, “tea”, “ted”, “ten”, “i”, “in”, and “inn”.如下图所示:
字典树主要有如下三点性质:
-
根节点不包含字符,除根节点意外每个节点只包含一个字符。
-
从根节点到某一个节点,路径上经过的字符连接起来,为该节点对应的字符串。
-
每个节点的所有子节点包含的字符串不相同。
字母树的插入(Insert)、删除( Delete)和查找(Find)都非常简单,用一个一重循环即可,即第i 次循环找到前i 个字母所对应的子树,然后进行相应的操作。实现这棵字母树,我们用最常见的数组保存(静态开辟内存)即可,当然也可以开动态的指针类型(动态开辟内存)。至于结点对儿子的指向,一般有三种方法:
1、对每个结点开一个字母集大小的数组,对应的下标是儿子所表示的字母,内容则是这个儿子对应在大数组上的位置,即标号;
2、对每个结点挂一个链表,按一定顺序记录每个儿子是谁;
3、使用左儿子右兄弟表示法记录这棵树。
三种方法,各有特点。第一种易实现,但实际的空间要求较大;第二种,较易实现,空间要求相对较小,但比较费时;第三种,空间要求最小,但相对费时且不易写。
class TrieNode {
public:
// Initialize your data structure here.
TrieNode *child[26];
bool isWord;
TrieNode() : isWord(false){
for (auto &a : child) a = NULL;
}
};
class Trie {
public:
Trie() {
root = new TrieNode();
}
// Inserts a word into the trie.
void insert(string s) {
TrieNode *p = root;
for (auto &a : s) {
int i = a - 'a';
if (!p->child[i]) p->child[i] = new TrieNode();
p = p->child[i];
}
p->isWord = true;
}
// Returns if the word is in the trie.
bool search(string key) {
TrieNode *p = root;
for (auto &a : key) {
int i = a - 'a';
if (!p->child[i]) return false;
p = p->child[i];
}
return p->isWord;
}
// Returns if there is any word in the trie
// that starts with the given prefix.
bool startsWith(string prefix) {
TrieNode *p = root;
for (auto &a : prefix) {
int i = a - 'a';
if (!p->child[i]) return false;
p = p->child[i];
}
return true;
}
private:
TrieNode* root;
};
code jam
2017
Problem A. Oversized Pancake Flipper
https://code.google.com/codejam/contest/dashboard?c=3264486#s=p0&a=0
反转煎饼,每次能且只能反转K块
题解:
https://code.google.com/codejam/contest/dashboard?c=3264486#s=a&a=0
Scoreboard:
https://code.google.com/codejam/contest/scoreboard?c=3264486#vf=1
异或的意思是 按位比较,位相同(0,0或1,1)时,结果为0,位不同时(0,1或1,0)结果为1
所以,0异或任何数A 结果还是A
A异或1时,A的最后一位是1,则会变为0,如果是0,则会变为1,因此,结果一定是非A
#include <bits/stdc++.h>
using namespace std;
int N, K;
char S[10000];
void _main(int TEST)
{
scanf("%s%d", S, &K);
N=strlen(S);
int ans=0;
for(int i=0; i+K-1<N; i++) if(S[i]=='-')
{
for(int j=0; j<K; j++)
S[i+j]^='-'^'+'; // change to '+';
ans++;
}
for(int i=0; i<N; i++) if(S[i]=='-')//if still remain '-', failed.
ans=-1;
if(ans==-1)
printf("IMPOSSIBLE\n");
else
printf("%d\n", ans);
}
int main()
{
freopen("A-small.in", "r", stdin);
freopen("A-small.out", "w", stdout);
// freopen("A-large.in", "r", stdin);
// freopen("A-large.out", "w", stdout);
int TEST;
scanf("%d", &TEST);
for(int i=1; i<=TEST; i++)
{
//cerr << i << endl;
printf("Case #%d: ", i);
_main(i);
}
return 0;
}