知识点:Hash、双指针
[1] int的范围
[7] stack、ascii
[20]str.substr(pos,n)注意n是子串长
[14]
代码基本都在这里了:https://github.com/ixsim/OJ
1.两数之和
- 朴素法
我的第一道LeetCode。上来就暴力解。我还纳闷呢,怎么输出结果和答案都一样。就是过不了。
原来是,时间复杂度为O(N)。过不了的。
- Hash O(nlogn)
哈希表Hash[x] 下标x表示x在nums中的下标。
注意“ map底层使用平衡树一类的数据结构进行实现,插入和查询是O(logn)级别的。
代码
1 | class Solution { |
上面这个版本更好理解。
然后看到这个版本更简洁。
1 | class Solution { |
- 知识点:
为啥要和 map.end()
比较呢?
修改和查找数据
(1)修改Map[“sunquan”]=11111;
(2)查找数据 用Map.find(key); 可以通过键来查。
切记不要用int value=Map[key];
这样会在Map中增加这个key,而value就是缺省值(int 为0,string为空字符串)。
通过方法(2),会返回迭代器的地址, key不存在的话迭代器的值为
Map.end()
初学map哈哈。
https://www.cnblogs.com/panweiwei/p/6657583.html
2 两数之和
easy
3 无重复字符的最长子串
不能判断到有重复字符就从0开始算啊。字符串的头尾不固定的。
比如
avadc
虽然a在第三个位置出现了。但是不能重新计数。前面的v也可以算的。- 很快就解决了这个问题。就是 计数的变量count 找到重复字符后,不置为0,而是置为 两个相同字符的坐标差。这样就包含了后面的字符。
- 新问题就是,从新计数的单词,之前的字母还在map中没清空。怎么办?
- 我设了一个开始坐标start,只有在map中且坐标大于这个start才算重复出现。
看下第一的答案:
1 | int lengthOfLongestSubstring(string s) { |
04二叉树的最大深度
必备
5最长回文子串
没想到我的方法效率还不错。
6.Z字形变换
水题。用一个flag记录存入的方向即可。详情看代码。
7.反转整数
- 正解
1 | int reverse(int x) { |
- Problems
第一次问题出在ans的类型上。没有存成
long
。输入是1534236469时,输出错误。
Int 的范围是 -2^31 ~ 2^31-1,即-2147483648~2147483647
输入1534236469输出应该是9646435461都就90多亿了。int最大存21亿。
所以应该输出零。而且这个数在ans存的时候要用
long
型,再和INT_MAX
判断一次再return。改了long之后。1032个用例就差一个过不了了。就是-2147483648。
-2147483648会被转成正2147483648。而正int里最大是2147483647。存不下2147483648 。所以特判了。
8.atoi
在C++里,长度不一样的String比较会是什么规则?
直接输入:
cout << "abc"<"bbbb";
这种情况注意了:比较的是两个const char*!实则比较的是他们的地址而已。真的相比较要用:
strcmp("abc","bbbb")
比较的时候:
- 先不管两个串的长度,一位一位的比下去。如果有一个串的相同位更大,立马返回结果。
- 当一个串比完,还都一样的时候,长的更大。
这题意思不大,就是把所有的情况都考虑到。反正我是没用到啥编程技巧。
9.回文数
- 解法
1 | class Solution { |
- Problems
开始忘了把x先存到tmp中。最后就直接判断
y==x
结果每次都是返回false。很尴尬。x在while中肯定会被改成0啊。
最后一个if只判断了true的情况,忘了写else😂😂😂
低级错误。见笑。
- 知识点 取消cin同步。取消cin与cout绑定。
在这题和翻转数字那题的优化解里都看到这么一断:
1 | //lambda 表达式,可以立即执行,在main函数之前执行,取消输入输出同步,较快输入输出速度 |
std::ios::sync_with_stdio(false)
这句语句是用来取消cin的同步,什么叫同步呢?就是iostream的缓冲跟stdio的同步。如果你已经在头文件上用了using namespace std;那么就可以去掉前面的std::了。
取消后就cin就不能和scanf,sscanf, getchar, fgets之类同时用了,否则就可能会导致输出和预期的不一样。
取消同步的目的,是为了让cin不超时,另外cout的时候尽量少用endl,换用”\n”,也是防止超时的方法。
当然,尽量用scanf,printf就不用考虑这种因为缓冲的超时了。
cin.tie(NULL)
取消cin与cout的绑定
1 | 把上一段代码加到我的解法前面,运行时间直接从120ms到了64ms。 |
再看这个解法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20static auto x = []() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
return 0;
}();
class Solution {
public:
bool isPalindrome(int x) {
stringstream ss;
ss << x;
string str;
ss >> str;
string strTmp = str;
reverse(str.begin(), str.end());
if (strTmp == str)
return true;
return false;
}
};存成字符串。然后用了个reverse翻转。STL里面啥都有啊。
10.正则表达式匹配
11盛最多水的容器
12整数转罗马数字
13.罗马数字转整数
- 无聊的一题
14.最长公共前缀
- 解
1 | string Prefix2(string a,string b){ |
我的解真是弱爆了。
Problems
第一次报错
“Runtime Error Message:reference binding to null pointer of type ‘struct value_type’
Last executed input: []
百度了一下。https://blog.csdn.net/zy2317878/article/details/78820900 特判:如果size()是0则返回””
边界值特殊值要考虑好啊。
第二次是输入只有1个单词的时候。因为我是自己写了个比较两个单词最长前缀的函数。所以输入只有一个的时候,直接返回了””。正确答案应该是返回这个单词。我又强行加了这么一种情况。
我的解法效率极低。下面去看看大神们怎么解吧。
优化解
1 | string longestCommonPrefix(vector<string>& strs) { |
知识点:
str.substr(x,y)
就是取子串。str.substr(0,0)
应该就是""
这个解的逻辑确实很清晰!
相同的逻辑,解答里还有一个0ms的写法就是
while((strs[0])[i])
14最长公共前缀
15三数之和
16最接近的三数之和
17电话号码的字母组合
18四数之和
19删除链表的倒数第N个节点
20.有效的括号
Problems
char
类型就用单引号啊!!!之前写
s[i] == "("
一直报错。我就是整不明白为啥报错。单引号啊!!!
vector.end()
是地址,而且还是最后一个元素后面的地址。所以最后一个元素应该是*(vector.end()-1)
遍历的话可以用
for(auto s:vector)
拿过题就用vector声明了一个栈做。不知道有
stack
都。NAIVE~判断”)}]”这三种情况的时候应该先看栈里是不是空。再看栈顶的元素。不然如果栈为空,取栈top()会跑不出来。
每次
return flase
之后都要记得break跳出循环啊vector中v[i]与v.at(i)的区别
1
2v[0]; // A
v.at[0]; // B如果v非空,A行和B行没有任何区别。
如果v为空或者下标越界,B行会抛出std::out_of_range异常,A行的行为未定义。
c++标准不要求vector::operator[]进行下标越界检查,原因是为了效率,总是强制下标越界检查会增加程序的性能开销。设计vector是用来代替内置数组的,所以效率问题也应该考虑。不过使用operator[]就要自己承担越界风险了。
如果需要下标越界检查,请使用at。
我的解效率特别差。看一下人家的
优化解
1 | class Solution { |
哎!简洁又效率。
先判断了长度是奇数返回false.为空返回false.
没有瞎判断字符是不是
'{([])}'
而是利用了ascii码。那为啥有 -1 有 -2 呢?
看了ascii码表你就知道了。
ASCII值 | 控制字符 | ASCII值 | 控制字符 | ASCII值 | 控制字符 | ASCII值 | 控制字符 |
---|---|---|---|---|---|---|---|
0 | NUT | 32 | (space) | 64 | @ | 96 | 、 |
1 | SOH | 33 | ! | 65 | A | 97 | a |
2 | STX | 34 | “ | 66 | B | 98 | b |
3 | ETX | 35 | # | 67 | C | 99 | c |
4 | EOT | 36 | $ | 68 | D | 100 | d |
5 | ENQ | 37 | % | 69 | E | 101 | e |
6 | ACK | 38 | & | 70 | F | 102 | f |
7 | BEL | 39 | , | 71 | G | 103 | g |
8 | BS | 40 | ( | 72 | H | 104 | h |
9 | HT | 41 | ) | 73 | I | 105 | i |
10 | LF | 42 | * | 74 | J | 106 | j |
11 | VT | 43 | + | 75 | K | 107 | k |
12 | FF | 44 | , | 76 | L | 108 | l |
13 | CR | 45 | - | 77 | M | 109 | m |
14 | SO | 46 | . | 78 | N | 110 | n |
15 | SI | 47 | / | 79 | O | 111 | o |
16 | DLE | 48 | 0 | 80 | P | 112 | p |
17 | DCI | 49 | 1 | 81 | Q | 113 | q |
18 | DC2 | 50 | 2 | 82 | R | 114 | r |
19 | DC3 | 51 | 3 | 83 | S | 115 | s |
20 | DC4 | 52 | 4 | 84 | T | 116 | t |
21 | NAK | 53 | 5 | 85 | U | 117 | u |
22 | SYN | 54 | 6 | 86 | V | 118 | v |
23 | TB | 55 | 7 | 87 | W | 119 | w |
24 | CAN | 56 | 8 | 88 | X | 120 | x |
25 | EM | 57 | 9 | 89 | Y | 121 | y |
26 | SUB | 58 | : | 90 | Z | 122 | z |
27 | ESC | 59 | ; | 91 | [ | 123 | { |
28 | FS | 60 | < | 92 | / | 124 | |
29 | GS | 61 | = | 93 | ] | 125 | } |
30 | RS | 62 | > | 94 | ^ | 126 | ` |
31 | US | 63 | ? | 95 | _ | 127 | DEL |
21 合并有序链表
解
不贴我的了。写的太烂了。新建了一个链表一个数一个数插进去的。
贴一个同效率的。简洁好多。
1 | /** |
~ 知识点
一个是建ListNode。声明节点的细节。
new struct
一个就是重要的技巧。别声明一个新指针为NULL。除非你开车很稳。
关于
NULL
和nullptr
:NULL
其实是int型的0,为了真正的空指针,c++11推出nullptr
可以先声明一个随意值的节点(比如-9999),然后在这个节点后面处理就好了。最后return时返回这个节点的next就好了。
Problems
输入是
[]和[0]
的时候不行。没考虑第一个链表就是空的情况。所以开头定义tmp就直接指向L1;重要!!!
新声明一个节点
new struct
。和新声明一个指针*p
不一样。这个问题要想清楚!!!
记得要先把头存起啦啊。不然你移来移去拿什么返回链表头。
循环遍历所有节点最好用
while(list->next)
。这样指针刚好停在最后一个节点。
递归的解法
1 | class Solution { |
合并两个链表。就是判断完头元素后。合并 剩下的部分 连接到 小的头里。
结束条件:
如果一个为Null(总是合并剩下的部分一定会遇到null)则返回另一个。
22括号生成
23合并K个排序链表
24两两交换链表中的节点
25k个一组翻转链表
26. 删除排序数组中的重复项
- 循环左移之后。记得这一轮就不要让标记位置走到下一个了。
- 传入空字符串的时候。我的程序会完全没有符合的条件。而导致没有返回值超时。以后要注意写条件的时候就想清楚会不会有特殊情况。
- sb了。没看题是排好序的。而且遍历的时候是遍历你返回值n的前n个。
27. 移除元素
吸收了上一题的答案。直接超越100%:
1 | int n = 0; |
28实现strStr()
29两数相除
30与所有单词相关联的字串
31下一个排列
32最长有效括号
33搜索旋转排序数组
34在排序数组中查找元素的第一个和最后一个位置
35. 搜索插入位置
PASS
36有效的数独
37解数独
38. 报数
水题不解释
39组合总和
40组合总和 II
41缺失的第一个正数
42接雨水
43字符串相乘
44通配符匹配
45跳跃游戏 II
46全排列
47全排列 II
48旋转图像
49字母异位词分组
- 排序的方法我想到了。需要注意,Go sort 包的用法
1 | sort.Slice(x, func(i,j int) bool{return x[i]<x[j]}) |
看了题解,知道了可以通过数字母出现次数的方法,然后尝试,
但是比较蠢,是把出现的次数拼接成了一个字符串:
比如 aac,拼成 201 代表 a 两次,c 一次,
这时候发现 有可能是 a 20 次,b 一次,拼出来也是 201,
于是又加了 # 作为分隔符。
变成: 2#0#1# 这种格式。
又去看了官方的代码,发现 Go 的 map,是可以把 [26]int 这样的数组作为 key 的,因此有了更好的解法。
就是统计完,不需要想出来一个规则表达式,完全靠数组作为 key 来判断是否曾经出现过。这一点学到了!