1.28学习总结
- 回文链表
- 环形链表
- 合并两个有序链表
回文链表
拿到这个题有两个想法,一个就是转数组去判断了再转回来,这样就是方便用数组随机访问特性。
第二个想法:用头插法再建立一个链表,然后再遍历,但是我感觉这和方法一没啥区别。
题目要求的是o(1)的空间,这我就没办法了,于是看题解。
看了题解:茅塞顿开,直接先找到链表的中间位置,然后将后半部分链表逆置。这样就方便比对元素了。题解有个关键的话:避免使用额外空间的方法就是改变输入。
func isPalindrome(head *ListNode) bool {
//找到中间结点
slow,fast:=head,head
for fast!=nil && fast.Next!=nil{
slow=slow.Next
fast=fast.Next.Next
}
//处理奇数结点的情况
if fast!=nil{
slow=slow.Next
}
//逆置后半部分
var pre *ListNode = nil
cur:=slow
for cur!=nil{
temp:=cur.Next
cur.Next=pre
pre = cur
cur=temp
}
//比对元素
fast=head
for pre!=nil{
if pre.Val!=fast.Val{
return false
}
pre=pre.Next
fast=fast.Next
}
return true
}
这个题能写出来的关键:
1.找中点,在哪里停?你要停下来的那个点具体是哪个点。奇数情况和偶数的情况要分情况处理吗,怎么分?
2.后半部分链表逆置,具体是怎么做。
3.比对元素的时候,终止条件是什么。
解答:
1.这个就必须举例子来看
偶数:1->2->2->1->nil,自己模拟一下,slow走一步,fast走两步。我们想要的状态应该是我这个slow最终指向后半部分,那就是只在后面那个2的地方。那么此时循环终止条件,根据模拟的结果应该是fast!=nil&&fast.Next!=nil,这样最终fast会指向nil然后就停下来了。
奇数:1->2->3->2->1->nil,我当时做的时候就没有我到底应该去指向什么位置。我的目的是我只要后半段,中间的这个元素在根本就不用比较。所以按照偶数的处理,fast最终指向最后一个1,slow指向3,此时我的目标还是后半段元素,这里我就可以做一个特判,这里和偶数的区别就是偶数的fast=nil,奇数的fast!=nil,所以根据这个区别我就可以写出特判,从而直接slow=slow.next,这样就指向了后半段。
2.我对逆置的应用还是理解有点少了,之前我就想歪了,歪到我想直接将这个后半部分原地逆置,这显然是不合理的,这样我必然会动到前面部分的指针,而我的目的我根本不需要这么原地逆置,我只要拿到后半段。所以当时这里没想清楚。所以这部分的逆置就直接按常规操作来。逆置了就拿到了后半部分的链表,接下来去比较即可,没必要原地逆置。
3.我第一次写的时候也错了,终止条件应该是pre!=nil,我第一次写的pre.next!=nil,这样就会导致最后一个元素我没比较,而且我当时没理解好,我用这个pre,我是拿这个pre在遍历,我去看pre.next,那是在拿pre.Next在遍历。这样搞我的结果肯定怎么都是错的。所以这里必须清楚。
环形链表
func hasCycle(head *ListNode) bool {
if head==nil || head.Next==nil{
return false
}
fast,slow:=head,head
for fast.Next!=nil && fast.Next.Next!=nil{
slow=slow.Next
fast=fast.Next.Next
if slow==fast{
return true
}
}
return false
}
写的时候就出一个问题
就是上面这个判head这里用了&&,主要是没想明白这里的逻辑,这里的逻辑应该是前者先满足,那么就直接返回false了。
而且关于短路的应用,||和&&这两个运算符都有短路的特性。我这里主要是短路的特性又搞混了。
合并两个有序链表
这个题的思路当时就直接想到了链表的做法,直接双指针就可以了
func mergeTwoLists(list1 *ListNode, list2 *ListNode) *ListNode {
dummyhead:=&ListNode{}
cur:=dummyhead
cur1:=list1
cur2:=list2
for cur1!=nil&&cur2!=nil{
if cur1.Val<=cur2.Val{
temp:=cur1
cur.Next=temp
cur=cur.Next
cur1=cur1.Next
}else{
temp:=cur2
cur.Next=temp
cur=cur.Next
cur2=cur2.Next
}
}
if cur1==nil{
cur.Next=cur2
}
if cur2==nil{
cur.Next=cur1
}
return dummyhead.Next
}
第一次就过了
这里总结一下思路:
我还是用了虚拟头结点,这样做是为了方便处理,最后返回dummyhead.Next就可以了
cur就是用于构造答案的,cur1扫描list1,cur2扫描list2。
我做的时候我还想了一个问题,因为有时候我对空间复杂度这方面有点疑问,我这里空间复杂度是o(1),这个链表只是个指针。