知识点: 摩尔投票算法
[169] reverse()的理解
[189] 位运算
136 string.erase()
[171]
101.对称二叉树
开始写成了判断节点的两个孩子是否相同。完全整错了题。
用两个前序遍历把结果存到vector里。一个先遍历左孩子,一个先遍历右孩子。然后比较两个vt相同。
- Problem,空节点的时候,不会存入vector,导致一些情况判错。解决方法:空节点存入-9999
正经的解法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20bool symmetric(TreeNode* left, TreeNode* right)
{
if (!left && !right)
{
return true;
}
if (!left || !right)
{
return false;
}
return left->val == right->val && symmetric(left->left, right->right) && symmetric(left->right, right->left);
}
bool isSymmetric(TreeNode* root)
{
if (!root)
{
return true;
}
return symmetric(root->left, root->right);
}
107二叉树的层次遍历 II
121/122 买股票1 买股票2
- 121:比较简单。但我第一次用的O(n2)。显得很没水平。只要记录最小值和最大值就可以了。不需要两层循环遍历的。
- 122:有了上一题的启发。很快解决。(本来想半天)
141环形链表
知识点:如果有环,快慢指针一定会相遇。可用递归法证明。
136只出现一次的数字
高端操作:位运算
- 延伸阅读:https://blog.csdn.net/bitboss/article/details/51594037
- 进阶1: 一个数组中,只有一个数字出现了一次,其他数字都出现了三次,找出这个出现了一次的数字;
- 进阶2:**<百度面试题>:在一个数组中,其他元素都是成对出现,只有两个数字只出现了一次,找出这两个数;** 剑指offer#40。已刷
151最小栈
- 可以用
*(vt.end()-1)
的方式取到vector的最后一个元素啊。
两个数组的交集 II
关于map的遍历:
- 如果输入的map下标不存在则会创建这个下标。
- map.find()是查的关键字
160 相交链表
我用了一个set保存A的每个地址。
然后对着B进行set.find()。过。关闭输入输出同步之后效率从29升到87~哈哈。
168 EXCELL表列名
就是输入1输出A 输入28输出AB
注意输入26时,余数为0。这种情况需要特判。
输入26时。n的循环也会多走一圈。需要特判。不然输入26会输出ZA。
每轮循环结束是
n = n/26
还是n = n-26
? 请思考清楚
171和168相对
string.erase(pos,len)
,从pos位置开始删除len个字符。len缺省则删除到末尾。返回string的一个引用。
比如str.erase(str.size()-5,5);
删除了后5个字符。注意是.size()-5 。就是用下标来控制的。
我个人更喜欢用 str = str.substr(pos1,pos2)
这种方式删除
169绝对众数
- 用map做感觉是水题。
但是在别人的解法里学到了摩尔投票算法:
首先请考虑最基本的摩尔投票问题,找出一组数字序列中出现次数大于总数1/2的数字(并且假设这个数字一定存在)。显然这个数字只可能有一个。摩尔投票算法是基于这个事实:每次从序列里选择两个不相同的数字删除掉(或称为“抵消”),最后剩下一个数字或几个相同的数字,就是出现次数大于总数一半的那个。
- 继续延伸:1/k众数
Ex:k=3。求1/3众数。注:这样的数可能不存在
1 |
|
172阶乘后的零
13的阶乘就已经超INT范围了。用了
long long
型之后,它给我输入了个30🙂🙂🙂思路有问题🙃
找到了规律。其实有几个零就是和因子里有几个5有关系。所以遇到 5、25、125、675~这种要处理,可是刁钻的问题出现了。测试用例给了一个1808548329。5的13次方是1220703125。我的算法可以给出答案。但是超时了。后面还有个过不了的用例2147483647。就是INT_MAX呗。超时了。我直接特判了这两个过的。
结果发现0ms的答案只有这么几行:
1
2
3
4
5
6int trailingZeroes(int n) {
long long sum=0;
for(long long i=5;i<=n;i=i*5)
sum=sum+n/i;
return sum;
}
这时候再回头看一下我自己写的【超时版】答案。其实不就是一个意思吗:
1 | int ans = n/5; //先除以5 |
189旋转数组
开始想用一个临时数组存原来的数。然后根据需要copy。
结果发现人家让空间复杂度O(1)原地完成。
想到了多次Reverse的方法。这个思路还是很清晰的。以下两点需要注意:
如vt的内容是 1 2 3 4 5 6 7
reverse(vt.begin(),vt.begin()+3)
执行后,反转的就是前三个数。变成:321 4567
虽然
vt.begin()+3
已经指向了4
这个元素。这也可以解释为什么
reverse(vt.begin(),vt.end())
在end()指向空的时候,为什么可以翻转整个vector。–>四个字:左闭右开!
输入的位移量大于数组长度的情况要考虑到,取余即可。(怕的是想不到)
283移动零
输入 0 1 0 3 2
输出 1 3 2 0 0
- 注意,用迭代器it控制,vt.erase(it) 时,删除了it指向的元素,且it会指向下一个it。
- 出现的问题:
- 开始我只用迭代器来控制遍历,当迭代器为end时终止遍历,没考虑到,我会不停地在vector尾部push_back(0),这样遍历永远都不会结束。
206 反转链表
我用递归做的。
思路是,把第一个节点取出来。然后从第二个开始反转,反转的结果再接上第一个节点。
Problems
开始我取第一个节点是直接一个指针指向head。这样虽然取到了。但是这个节点的next不是NULL啊。而是2号到最后。
后来用的方法是new一个新的空间。(相当于是取出来了第一个节点的值吧)
然后再把后面的反转之后,接上这个new的节点。
解
1 | ListNode* reverseList(ListNode* head) { |
要点就是我备注的两个地方了。
但是我这个写法。光顾着递归了。效率是排行倒数。人家第一的递归写法:
1 | if(head==NULL||head->next==NULL) |
这就是另一个境界的思想问题了。
他的解法也是把第一个取出来。把后面的反转了接上第一个。
但是,人家是在地址上操作的。我是新开辟空间的。
直接把两个一组。head->next->next=head;
这句是精华。
然2号的下一个变成1号,再让1号的下一个变成null。成功调换1-2的位置为2-1-null、
而2号其实在上一次的递归中,已经被它的上一个3号所指向。即3->next就是2号、
启发。递归的时候可以倒着思考问题。
思路是把第一个拿出来。再把剩下的做reverse()处理后返回。
返回的时候返回的就是已经反转完成的链表的头。别想别的。
思考最后递归的倒数第二层是什么情况(比如这题就是还剩俩节点)。
203 删除链表中的节点
和237题不同的是这个题是给了值。237题给的是节点。
感悟和上一个#83题查不多。就是想删除某个节点。只把 cur指针赋NULL是不行的。因为上一个节点的next 还指着 之前 cur的地址啊。cur是为空了,上一个节点的next不是空啊。
因为觉得删最后一个节点的情况不好写。转递归法一气呵成哈哈。
1 | ListNode* removeElements(ListNode* head, int val) { |
当然效率一般。超越了96%。我再参考下别的。
处理最后一个节点的方法。可以再声明一个指针p。一个指针往下移。p不移动。这样就可以定位倒数第二的节点。
下面这个解法很清晰了。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23if (head == NULL)
return head;
ListNode phead(0);
ListNode *ptemp = head;
ListNode *p = &phead; //phead是一个结构体。所以要指向它的地址。
//也可以在之前就声明ListNode* phead = new ListNode(9999);就不用取地址了。
phead.next = ptemp;
while (1)
{
if (ptemp->val == val)
{
p->next = ptemp->next;
ptemp = p->next;
}
else
{
p = ptemp;
ptemp = ptemp->next;
}
if (ptemp==NULL)
break;
}
return phead.next;
234 回文链表
注意。长度为1的链表也是回文的。
我的方法比较笨。先跑一遍记录有多少个数。再遍历前半部分,把数存到栈里。再遍历后半部分。挨个出栈。
下面看一个知识点,
快慢指针
知识点:快指针走两步。慢指针走一步。快指针到链尾。慢指针到中间。
1 | bool isPalindrome(ListNode* head) { |
- 最后说一下排行第一的方法。人家没存到栈里。存到了向量里。然后直接用坐标定位来判断首尾是否一样。我真的是太定向思维了。看到是从中间往两侧判断就知道用栈。辣鸡~
707设计链表
不想做😛😛😛
【链表+简单】刷完~
876 链表的中间节点
简单。计数器判断。