4.29LeetCode

说一下,今天开始代码尽量准备用java写了,感觉好不习惯。。

198. House Robber

  1. 打家劫舍
    比较简单的动态规划题目。
    dp[i]=max(dp[i-1],dp[i-2]+nums[i])
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// dp[i]表示前n户并且抢劫过第n家的max,感觉自己想复杂了。。。也可以通过。
// class Solution {
// public:
// int rob(vector<int>& nums) {
// if(nums.empty()) return 0;
// if(nums.size()==1) return nums[0];
// if(nums.size()==2) return max(nums[0],nums[1]);
// vector<int> dp;
// dp.resize(nums.size());
// dp[0]=nums[0]; dp[1]=nums[1]; dp[2]=nums[0]+nums[2];
// for(int i=3;i<nums.size();i++)
// dp[i]=max(dp[i-2]+nums[i],dp[i-3]+nums[i]);
// return max(dp[nums.size()-1],dp[nums.size()-2]);
// }
// };


class Solution {
public:
int rob(vector<int>& nums) {
if(nums.empty()) return 0;
if(nums.size()==1) return nums[0];
vector<int> dp;
dp.resize(nums.size());
dp[0]=nums[0]; dp[1]=max(nums[0],nums[1]);
for(int i=2;i<nums.size();i++)
dp[i]=max(dp[i-1],dp[i-2]+nums[i]);
return dp[nums.size()-1];
}
};

384. Shuffle an Array

  1. 打乱数组
    第一次写java,感觉好难啊。。踩了好多坑,数组的深浅拷贝和伪随机函数等等.. 慢慢学吧 注释的是评论区大佬的答案。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
class Solution {
int[] Arr;
int[] Nature;
public Solution(int[] nums) {
Arr=nums;
Nature= Arrays.copyOf(Arr, Arr.length);
}

/** Resets the array to its original configuration and return it. */
public int[] reset() {
for(int i=0;i<Arr.length;i++)
Arr[i]=Nature[i];
return Arrays.copyOf(Arr, Arr.length);
}

/** Returns a random shuffling of the array. */
public int[] shuffle() {
for(int i=Arr.length-1;i>0;i--){
Random rand=new Random();
int t=rand.nextInt(i+1); //随机数生成范围要注意
int temp=Arr[t];
Arr[t]=Arr[i];
Arr[i]=temp;
}
return Arr;
}
}

/**
* Your Solution object will be instantiated and called as such:
* Solution obj = new Solution(nums);
* int[] param_1 = obj.reset();
* int[] param_2 = obj.shuffle();
*/


// class Solution {
// int[] nums;

// public Solution(int[] nums) {
// this.nums = nums;
// }

// /** Resets the array to its original configuration and return it. */
// public int[] reset() {
// return nums;
// }

// /** Returns a random shuffling of the array. */
// public int[] shuffle() {
// int[] result = Arrays.copyOf(nums, nums.length);
// Random rand=new Random();
// for(int i = nums.length - 1; i > 0; i--) {
// int n = rand.nextInt(i + 1);
// // swap n and i
// int tmp = result[n];
// result[n] = result[i];
// result[i] = tmp;
// }
// return result;
// }
// }

412. Fizz Buzz

java:

1
2
3
4
5
6
7
8
9
10
11
12
13
class Solution {
public List<String> fizzBuzz(int n) {
List<String> res=new ArrayList<String>();
for(int i=1;i<=n;i++){
if(i%3==0&&i%5==0)
res.add("FizzBuzz");
else if(i%3==0&&i%5!=0) res.add("Fizz");
else if(i%5==0&&i%3!=0) res.add("Buzz");
else res.add(Integer.toString(i));
}
return res;
}
}

204. Count Primes

计数质数
一开始的想法就是判断从1-n的每个数是否为质数,时间复杂度O(n^2)
最简单的方法当然通过不了,参考了某大佬的一篇博客进行剪枝
附连接:判断一个数是不是质数(素数),3种方式介绍

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Solution {
public int countPrimes(int n) {
int res=0;
for(int i=1;i<n;i++)
if(isPrime(i)) res++;
return res;

}
public static boolean isPrime(int num) {
if (num <= 3) {
return num > 1;
}
// 不在6的倍数两侧的一定不是质数
if (num % 6 != 1 && num % 6 != 5) {
return false;
}
int sqrt = (int) Math.sqrt(num);
for (int i = 5; i <= sqrt; i += 6) {
if (num % i == 0 || num % (i + 2) == 0) {
return false;
}
}
return true;
}

}

然后根据题目下面的提示,了解了埃拉托色尼筛选法(质数问题)。唯一疑惑就是明明应该可以从i*i开始覆盖,不知道为什么总会报错说数组越界。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Solution {
public int countPrimes(int n) {
if(n<3) return 0;
int res=0;
int[] temp=new int[n];
for(int i=0;i<n;i++)
temp[i]=i;
for(int i=2;i<n;i++){
if(temp[i]==i){
res++;
for(int j=2;j*i<n;j++)
temp[j*i]=i;
}
}
return res;

}
}

326. Power of Three

递归解法很常规

1
2
3
4
5
6
7
class Solution {
public boolean isPowerOfThree(int n) {
if(n==1) return true;
else if(n%3!=0||n==0) return false;
else return isPowerOfThree(n/3);
}
}

评论区大佬的两种解法:

1
2
3
4
5
6
7
class Solution {
public boolean isPowerOfThree(int n) {
String str=Integer.toString(n,3); //将n由十进制转化为3进制(java进制转换的写法,学到了)
boolean result = str.matches("^10*$");//^表示正则开始,$表示正则结束,意思为匹配1开头中间可以无数个0的字符
return result;
}
}
1
2
3
4
5
class Solution {
public boolean isPowerOfThree(int n) {
return n > 0 && 1162261467%n == 0;
}
}

13. Roman to Integer

写得太丑陋了。。不忍直视。。。有空一定重新用switch写下。。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
class Solution {
public int romanToInt(String s) {
int res=0;
int i=0;
while(i<s.length()){
if(s.charAt(i)=='M') {
res+=1000;
i++;
continue;
}
if(s.charAt(i)=='D'){
res+=500;
i++;
continue;
}
if(s.charAt(i)=='C'){
if(i+1<s.length()&&s.charAt(i+1)=='D'){
res+=400;
i+=2;
}
else if(i+1<s.length()&&s.charAt(i+1)=='M'){
res+=900;
i+=2;
}
else {
res+=100;
i++;
}
continue;
}
if(s.charAt(i)=='L'){
res+=50;
i++;
continue;
}
if(s.charAt(i)=='X'){
if(i+1<s.length()&&s.charAt(i+1)=='L'){
res+=40;
i+=2;
}
else if(i+1<s.length()&&s.charAt(i+1)=='C'){
res+=90;
i+=2;
}
else {
res+=10;
i++;
}
continue;
}
if(s.charAt(i)=='V'){
res+=5;
i++;
continue;
}
if(s.charAt(i)=='I'){
if(i+1<s.length()&&s.charAt(i+1)=='V'){
res+=4;
i+=2;
}
else if(i+1<s.length()&&s.charAt(i+1)=='X'){
res+=9;
i+=2;
}
else {
res+=1;
i++;
}
continue;
}
}
return res;
}
}

191. Number of 1 Bits

为什么java里面没有unsignedint啊??????
学了了评论区大佬的解法,体会了下n=n&(n-1)的妙用(每次可以消掉一个1).

1
2
3
4
5
6
7
8
9
10
11
public class Solution {
// you need to treat n as an unsigned value
public int hammingWeight(int n) {
int count = 0;
while (n != 0) {
count++;
n = n & (n - 1);
}
return count;
}
}

4.28LeetCode

38. Count and Say

  1. 报数
    emmmmm.题目比较难读懂,读懂很简单啦。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class Solution {
public:
string countAndSay(int n) {
string res="1";
for(int i=1;i<n;i++)
res=next(res);
return res;
}
string next(string n) {
int i=0;
string res;
while(i<n.length()){
char temp=n[i];
int num=1;
while(1){
if(i+1!=n.length()&&n[i+1]==n[i])
{
num++;
i++;
}
else break;
}
res+=to_string(num);
res+=temp;
i++;
}
return res;
}
};

237. Delete Node in a Linked List

  1. 删除链表中的节点
    感觉还是思路被桎梏了哈哈,说到删除节点第一时间想的永远是让被删除的前一个结点next指向被删除的next,为什么不换个思路去重新生成从被删除开始之后的整个链表呢
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Solution {
public:
void deleteNode(ListNode* node) {
ListNode* p=node;
while(p->next){
p->val=p->next->val;
p=p->next;
}
while(node->next!=p)
node=node->next;
node->next=nullptr;
return;
}
};

88. Merge Sorted Array

  1. 合并两个有序数组
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
class Solution {
public:
void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
int i=0,j=0;
vector<int> temp;
while(i<m&&j<n){
if(nums1[i]<=nums2[j])
{
temp.push_back(nums1[i]);
i++;
}else{
temp.push_back(nums2[j]);
j++;
}
}
if(i!=m){
while(i!=m){
temp.push_back(nums1[i]);
i++;
}
}
if(j!=n){
while(j!=n){
temp.push_back(nums2[j]);
j++;
}
}
i=0;
for(int it:temp){
nums1[i]=it;
i++;
}
return;
}
};

70. Climbing Stairs

爬楼梯
斐波那契数列。。

1
2
3
4
5
6
7
8
9
10
11
12
class Solution {
public:
int climbStairs(int n) {
if(n==1) return 1;
vector<int> dp;
dp.resize(n);
dp[0]=1;dp[1]=2;
for(int i=2;i<n;i++)
dp[i]=dp[i-1]+dp[i-2];
return dp[n-1];
}
};

53. Maximum Subarray

  1. 最大子序和
    这题实在是太难了。。。想了一上午都没想明白,说到底还是自己太菜了。。。到现在也只是勉强能理解标准答案。
    评论区大佬解答:这道题难度不该是easy 这道题的一开始我想到的是暴力的滑窗去做,复杂度O(n^2),显然达不到题目中要求的复杂度 这道题根据题目关键词,“最大”“连续”,可以判断是一道动态规划,附上这道题目的wiki链接https://zh.wikipedia.org/wiki/%E6%9C%80%E5%A4%A7%E5%AD%90%E6%95%B0%E5%88%97%E9%97%AE%E9%A2%98 方法如下:
    1.定义一个函数f(n),以第n个数为结束点的子数列的最大和,存在一个递推关系f(n) = max(f(n-1) + A[n], A[n]);
    2.将这些最大和保存下来后,取最大的那个就是,最大子数组和。因为最大连续子数组 等价于 最大的以n个数为结束点的子数列和
1
2
3
4
5
6
7
8
9
10
11
12
13
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int tempmax,res;
res=nums[0];
tempmax=0;
for(int i=0;i<nums.size();i++){
tempmax=max(tempmax+nums[i],nums[i]);
res=max(res,tempmax);
}
return res;
}
};

4.27LeetCode

26. Remove Duplicates from Sorted Array

从排序数组中删除重复项
双指针法解决。当数值不同且不指向同一个时替换。写的有点丑陋,可以利用nums[i]的值去替代temp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Solution {
public:
int removeDuplicates(vector<int>& nums) {
if(nums.empty()) return 0;
int i=j=0;
int temp=nums[i];
int res=1;
while(j<nums.size()){
if(temp<nums[j]){
res++;
if(i!=j)
{
i++;
nums[i]=nums[j];
}
temp=nums[j];
}
j++;
}
return res;
}
};

121. Best Time to Buy and Sell Stock

买卖股票的最佳时机
动态规划 前i天的最大收益 = max{前i-1天的最大收益,第i天的价格-前i-1天中的最小价格}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Solution {
public:
int maxProfit(vector<int>& prices) {
if(prices.empty()) return 0;
vector<int> dp;
dp.resize(prices.size());
dp[0]=0;
int minp=prices[0];
for(int i=1;i<prices.size();i++){
if(prices[i]<=prices[i-1])
dp[i]=dp[i-1];
else if(prices[i]-minp>dp[i-1])
dp[i]=prices[i]-minp;
else dp[i]=dp[i-1];
minp=min(minp,prices[i]);
}
return dp[prices.size()-1];
}
};

122. Best Time to Buy and Sell Stock II

  1. 买卖股票的最佳时机 II
    贪心没啥思路,偷看了评论区的答案:[7, 1, 5, 6] 第二天买入,第四天卖出,收益最大(6-1),所以一般人可能会想,怎么判断不是第三天就卖出了呢? 这里就把问题复杂化了,根据题目的意思,当天卖出以后,当天还可以买入,所以其实可以第三天卖出,第三天买入,第四天又卖出((5-1)+ (6-5) === 6 - 1)。所以算法可以直接简化为只要今天比昨天大,就卖出。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Solution {
public:
int maxProfit(vector<int>& prices) {
if(prices.empty()) return 0;
int res=0;
int pricenow=prices[0]; //默认持有价格
for(int i=1;i<prices.size();i++){
if(prices[i]<=pricenow) //当天价格比你持有的低,直接放弃之前的
pricenow=prices[i];
else{
res+=prices[i]-pricenow;
pricenow=prices[i];
}
}
return res;
}
};

48. Rotate Image

旋转图像
虽然是道medium题,但是感觉其实也没很难。。想了很久才明白旋转规则。(四个结点旋转)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Solution {
public:
void rotate(vector<vector<int>>& matrix) {
if(matrix.empty()) return;
int n=matrix.size();
for(int i=0;i<n/2;i++){
for(int j=i;j<n-i-1;j++){
int temp=matrix[i][j];
matrix[i][j]=matrix[n-1-j][i];
matrix[n-1-j][i]=matrix[n-1-i][n-1-j];
matrix[n-1-i][n-1-j]=matrix[j][n-1-i];
matrix[j][n-1-i]=temp;
}
}
return;
}
};

242. Valid Anagram

  1. 有效的字母异位词
    建立字母表 再比较。 也可以用map去做。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Solution {
public:
bool isAnagram(string s, string t) {
int a[26]={0};
int b[26]={0};
for(int i=0;i<s.length();i++)
a[s[i]-'a']++;
for(int i=0;i<t.length();i++)
b[t[i]-'a']++;
for(int i=0;i<26;i++)
if(a[i]!=b[i]) return false;
return true;
}
};

125. Valid Palindrome

  1. 验证回文串
    双指针法,感觉贴题目好有成就感。。题目不难,比较繁琐的是大小写的转换以及干扰字符去除的写法。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Solution {
public:
bool isPalindrome(string s) {
if(s.empty()) return true;
int i=0,j=s.length()-1;
while(i<j){
while(1){
if((s[i]>='0'&&s[i]<='9')||(s[i]>='a'&&s[i]<='z')||(s[i]>='A'&&s[i]<='Z')||i==j) break;
i++;
}
while(1){
if((s[j]>='0'&&s[j]<='9')||(s[j]>='a'&&s[j]<='z')||(s[j]>='A'&&s[j]<='Z')||i==j) break;
j--;
}
if(i==j) break;
char p=s[i],q=s[j];
if(p>='A'&&p<='Z') p+=32;
if(q>='A'&&q<='Z') q+=32;
if(p!=q) return false;
i++;
j--;
}
return true;

}
};

8. String to Integer (atoi)

  1. 字符串转换整数 (atoi)
    还是属于比较简单的medium主要考察一个细心把。。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Solution {
public:
int myAtoi(string str) {
long long res=0;
if(str.empty()) return 0;
int i;
for(i=0;i<str.length();i++)
if(str[i]!=' ') break;
if(i==str.length()||(str[i]<'0'&&str[i]!='-'&&str[i]!='+')||str[i]>'9') return 0;
char temp=str[i];
if(str[i]=='-'||str[i]=='+') i++;
while(i<str.length()){
if(str[i]>='0'&&str[i]<='9')
{
if(res>pow(2,31)-1) return temp=='-'?INT_MIN:INT_MAX;
res=res*10+(int)(str[i]-'0');
i++;
}
else break;
}
if(temp=='-') res=res*(-1);
if(res>pow(2,31)-1) return INT_MAX;
if(res<pow(2,31)*(-1)) return INT_MIN;
return res;
}
};

28. Implement strStr()

实现strStr()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 我枯了,明明是道ez题,居然随便写写过不了。。。还要剪枝。。

class Solution {
public:
int strStr(string haystack, string needle) {
if(needle.empty()) return 0;
int n1=haystack.length(),n2=needle.length();
if(n2>n1) return -1;
int i=0;
while(i+n2<=haystack.length()){
int t=i;
int j=0;
for( j=0;j<needle.length();j++)
{
if(haystack[t]!=needle[j]) break;
t++;
}
if(j==needle.length()) return i;
i++;
}
return -1;
}
};

4.26LeetCode

590. N-ary Tree Postorder Traversal

N叉树的后序遍历
解法一:递归

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/*
// Definition for a Node.
class Node {
public:
int val;
vector<Node*> children;

Node() {}

Node(int _val, vector<Node*> _children) {
val = _val;
children = _children;
}
};
*/
class Solution {
public:
vector<int> postorder(Node* root) {
vector<int> res;
help(root,res);
return res;
}
void help(Node* p,vector<int>& res){
if(!p) return ;
for(auto i:p->children)
help(i,res);
res.push_back(p->val);
}
};

解法二:迭代我们也可以使用迭代的方法来做,这里有个小trick,写法跟先序遍历十分的像,不同的就是每次把从stack中取的结点的值都加到结果res的最前面,还有就是遍历子结点数组的顺序是正常的顺序,而前序遍历是从子结点数组的后面往前面遍历,这点区别一定要注意。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Solution {
public:
vector<int> postorder(Node* root) {
vector<int> res;
help(root,res);
return res;
}
void help(Node* p,vector<int>& res){
if(!p) return ;
for(auto i:p->children)
help(i,res);
res.push_back(p->val);
}
};

429. N-ary Tree Level Order Traversal

层次遍历,没啥好说的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Solution {
public:
vector<vector<int>> levelOrder(Node* root) {
vector<vector<int>> res;
if(!root) return res;
deque<Node*> temp;
temp.push_back(root);
while(!temp.empty()){
int size=temp.size();
vector<int> t;
for(int i=0;i<size;i++){
auto it=temp.front();
temp.pop_front();
t.push_back(it->val);
for(auto j:it->children)
temp.push_back(j);
}
res.push_back(t);
t.clear();
}
return res;
}
};

559. Maximum Depth of N-ary Tree

  1. N叉树的最大深度

递归非常简单。。没啥好说的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Solution {
public:
int maxDepth(Node* root) {
int res=0;
help(root,0,res);
return res;
}

void help(Node* p,int s,int& res) {
if(!p) return;
s++;
res=s>res? s:res;
for(auto it:p->children)
help(it,s,res);
}
};

208. Implement Trie (Prefix Tree)

比较简单的medium题了,就是比较繁琐。在定义前缀树的时候要先去检查是否已经存在该结点。感觉还是对map的使用不够熟练。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
class Node {
public:
bool isWord=false;
unordered_map<char,Node*> next;
Node() {
isWord=false;
}
Node(unordered_map<char,Node*> _next){
next=_next;
isWord=false;
}
};
class Trie {
public:
Node* root;
/** Initialize your data structure here. */
Trie() {
root=new Node();
}

/** Inserts a word into the trie. */
void insert(string word) {
Node* temp=root;
for(int i=0;i<word.length();i++){
auto it=temp->next.find(word[i]);
if(it==temp->next.end()){
temp->next[word[i]]=new Node();
temp=temp->next[word[i]];
}else temp=temp->next[word[i]];

}
temp->isWord=true;
}

/** Returns if the word is in the trie. */
bool search(string word) {
Node* temp=root;
for(int i=0;i<word.length();i++){
auto it=temp->next.count(word[i]);
if(!it) return false;
temp=temp->next[word[i]];
}
if(temp->isWord) return true;
return false;
}

/** Returns if there is any word in the trie that starts with the given prefix. */
bool startsWith(string prefix) {
Node* temp=root;
for(int i=0;i<prefix.length();i++){
if(temp->next.count(prefix[i])==0) return false;
temp=temp->next[prefix[i]];
}
return true;
}
};

677. Map Sum Pairs

  1. 键值映射
    和上题类似,区别在于用递归思想求前缀总和。 考虑过在每个结点都写入当前值的方法,但是感觉这样每次插入新结点都需要去更新整个树,复杂度欠缺考虑。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    class Node{
    public:
    int num=0;
    unordered_map<char,Node*> next;
    Node() {}
    Node(unordered_map<char,Node*> _next){
    next=_next;
    }
    };
    class MapSum {
    public:
    Node *root;
    /** Initialize your data structure here. */
    MapSum() {
    root=new Node();
    }

    void insert(string key, int val) {
    Node *temp=root;
    for(int i=0;i<key.length();i++){
    auto it=temp->next.find(key[i]);
    if(it==temp->next.end()){
    temp->next[key[i]]=new Node();
    temp=temp->next[key[i]];
    }
    else temp=temp->next[key[i]];
    }
    temp->num=val;
    }

    int sum(string prefix) {
    Node *temp=root;
    for(int i=0;i<prefix.length();i++){
    auto it=temp->next.find(prefix[i]);
    if(it==temp->next.end()) return 0;
    else temp=temp->next[prefix[i]];
    }
    return help(temp);
    }

    int help(Node *p){
    int sum=p->num;
    for(auto it=p->next.begin();it!=p->next.end();it++)
    sum+=help(it->second);
    return sum;
    }
    };

648. Replace Words

  1. 单词替换
    写得有些自闭,不想说话。逻辑不难,主要是对于C++中string类的运用暂时还有所欠缺,特别对于一个长句子的处理。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
class Node {
public:
bool isWord=false;
unordered_map<char,Node*> next;
Node() {
isWord=false;
}
Node(unordered_map<char,Node*> _next){
next=_next;
isWord=false;
}
};
class Trie {
public:
Node* root;
/** Initialize your data structure here. */
Trie() {
root=new Node();
}

/** Inserts a word into the trie. */
void insert(string word) {
Node* temp=root;
for(int i=0;i<word.length();i++){
auto it=temp->next.find(word[i]);
if(it==temp->next.end()){
temp->next[word[i]]=new Node();
temp=temp->next[word[i]];
}else temp=temp->next[word[i]];

}
temp->isWord=true;
}

/** Returns if the word is in the trie. */
bool search(string word) {
Node* temp=root;
for(int i=0;i<word.length();i++){
auto it=temp->next.count(word[i]);
if(!it) return false;
temp=temp->next[word[i]];
}
if(temp->isWord) return true;
return false;
}

/** Returns if there is any word in the trie that starts with the given prefix. */
bool startsWith(string prefix) {
Node* temp=root;
for(int i=0;i<prefix.length();i++){
if(temp->next.count(prefix[i])==0) return false;
temp=temp->next[prefix[i]];
}
return true;
}
};
class Solution {
public:
string replaceWords(vector<string>& dict, string sentence) {
Trie tire;
vector<string> temp;
for(string it:dict) tire.insert(it);
int i=0;
string t;
for(int i=0;i<sentence.length();i++){
if(sentence[i]!=' ') {
t+=sentence[i];
}
else{
temp.push_back(t);
t.clear();
}
}
temp.push_back(t);
for(int it=0;it<temp.size();it++){
Node *p=tire.root;
string repre;
for(int i=0;i<temp[it].length();i++){
if(p->isWord){
temp[it]=repre;
break;
}
auto it1=p->next.find(temp[it][i]);

if(it1!=p->next.end()){
p=p->next[temp[it][i]];
}
else break;
repre+=temp[it][i];
}
repre.clear();
}
string res=temp[0];
for(int i=1;i<temp.size();i++)
res+=' '+temp[i];
return res;
}
};

4.25LeetCode

总结: 昨天晚上被蚊子咬到睡不着觉,好不容易进入梦乡,恍惚间又听到噗通一声,我当时就料想到是手机掉到床柜后面去了,于是早上七点多钟又爬起来翻箱倒柜找手机关闹钟。
所以意料当中地今天上午下午摸鱼只做了三条题目,都是比较ez的,晚上划水搭建了下博客。

701. Insert into a Binary Search Tree

Given the root node of a binary search tree (BST) and a value to be inserted into the tree, insert the value into the BST. Return the root node of the BST after the insertion. It is guaranteed that the new value does not exist in the original BST.

Note that there may exist multiple valid ways for the insertion, as long as the tree remains a BST after insertion. You can return any of them.

For example,

Given the tree:

    4
   / \
  2   7
 / \
1   3

And the value to insert: 5

You can return this binary search tree:

     4
   /   \
  2     7
 / \   /
1   3 5

This tree is also valid:

     5
   /   \
  2     7
 / \   
1   3
     \
      4

解答:
方案1 递归解决

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/**
* 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:
TreeNode* insertIntoBST(TreeNode* root, int val) {
if(!root) return new TreeNode(val);
if(val > root->val){
if(root->right==nullptr) root->right=new TreeNode(val);
else insertIntoBST(root->right,val);
}
else if(val < root->val){
if(root->left==nullptr) root->left=new TreeNode(val);
else insertIntoBST(root->left,val);
}
return root;
}
};

方案2 迭代求解,用时明显短于递归

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Solution {
public:
TreeNode* insertIntoBST(TreeNode* root, int val) {
if(!root) return new TreeNode(val);
TreeNode *p=root;
while(1){
if(val<p->val&&p->left)
p=p->left;
else if(val>p->val&&p->right)
p=p->right;
else break;
}
if(p->val <val) p->right=new TreeNode(val);
else p->left=new TreeNode(val);
return root;
}
};

原题中特地强调,可以改变树的结构,但是相对来说比较复杂,翻了翻评论区并没有这么写的解答,我思考了下,感觉与平衡二叉树的删除类似,在找到其应该插入位置后根据是否存在左右子树分类谈论。二叉树实在是太复杂啦!

235. Lowest Common Ancestor of a Binary Search Tree

  1. 二叉搜索树的最近公共祖先
    Given a binary search tree (BST), find the lowest common ancestor (LCA) of two given nodes in the BST.

According to the definition of LCA on Wikipedia: “The lowest common ancestor is defined between two nodes p and q as the lowest node in T that has both p and q as descendants (where we allow a node to be a descendant of itself).”

Given binary search tree: root = [6,2,8,0,4,7,9,null,null,3,5]

Example 1:

Input: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 8
Output: 6
Explanation: The LCA of nodes 2 and 8 is 6.

Example 2:

Input: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 4
Output: 2
Explanation: The LCA of nodes 2 and 4 is 2, since a node can be a descendant of itself according to the LCA definition.

Note:

All of the nodes’ values will be unique.
p and q are different and both values will exist in the BST.

解法: 递归实在是太好写啦,主要注意其二叉搜索树的特性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/**
* 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:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
if(!root) return nullptr;
if(p->val<root->val && q->val>root->val) return root;
if(p->val>root->val && q->val<root->val) return root;
if(p==root||q==root) return root;
if(p->val<root->val && q->val<root->val) return lowestCommonAncestor(root->left,p,q);
if(p->val>root->val && q->val>root->val) return lowestCommonAncestor(root->right,p,q);
return root;
}
};

589. N-ary Tree Preorder Traversal

  1. N叉树的前序遍历

一开始写了个递归版本,发现速度很慢,想写迭代版本,但是感觉和二叉树又不太一样 参考了下评论区大神的思路 豁然开朗 随便写写写下来,
发现时间还是特别高! 非常生气地拿了80ms的源码来跑,结果虽然比我的好,还是很高。 就有点懵逼了。

感觉这个迭代写法还是可以学习一下,和之前常写的二叉树的前序遍历迭代版本不太相同。(对栈的使用)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
/*
// Definition for a Node.
class Node {
public:
int val;
vector<Node*> children;

Node() {}

Node(int _val, vector<Node*> _children) {
val = _val;
children = _children;
}
};
*/
// class Solution {
// public:
// vector<int> preorder(Node* root) {
// vector<int> res;
// help(root,res);
// return res;
// }
// void help(Node* p,vector<int>& res){
// if(!p) return;
// res.push_back(p->val);
// for(auto it:p->children)
// help(it,res);
// }
// };

// class Solution {
// public:
// vector<int> preorder(Node* root) {
// stack<Node*> stk;
// vector<int> res;
// if(!root) return res;
// Node* p=root;
// stk.push(p);
// while(!stk.empty()){
// p=stk.top();stk.pop();
// res.push_back(p->val);
// if(p->children.empty())
// continue;
// else{
// for(auto it=p->children.rbegin();it!=p->children.rend();it++)
// stk.push(*it);
// }
// }
// return res;


// }
// };



class Solution {
public:
vector<int> preorder(Node* root) {
vector<int> res;
if(root == nullptr) return res;

stack<Node*> st;

st.push(root);

while(!st.empty())
{
Node* t = st.top();
st.pop();
res.push_back(t->val);
for(auto r = t->children.rbegin(); r != t->children.rend(); r++)
{
st.push(*r);
}
}

return res;
}
};

写在开博前的话

博客作为一个逐渐被时代淘汰的产物,或许已经失去了其存在的必要。与我而言,这里可以是二十年前的树洞,十年前的日记本,五年前的笔记。

步入大三下学期以来,的确感受到了对未来的迷茫与无助。开这个博客的目的,主要还是希望自己能够坚持每日更新所学知识到其上,不定期可能更新一些自己的一些思考,理念,烦心事种种。

希望自己明年这个时候,再回头看这个博客时,有所收获!祝愿各位在抵达路途的末端,都不会后悔。

我的迷茫和胆怯也一直都在,但我告诉我自己,就算是万丈深渊,走下去,也是前程万里。

Hello World

这是个markdown语法示例,我懒得删了。以后还可以参考下。
Welcome to Hexo! This is your very first post. Check documentation for more info. If you get any problems when using Hexo, you can find the answer in troubleshooting or you can ask me on GitHub.

Quick Start

Create a new post

1
$ hexo new "My New Post"

More info: Writing

Run server

1
$ hexo server

More info: Server

Generate static files

1
$ hexo generate

More info: Generating

Deploy to remote sites

1
$ hexo deploy

More info: Deployment

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×