1.28算法学习总结

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),这个链表只是个指针。

  • 29
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值