leetcode刷题记录day013:141和234

141、难度简单:

要求:O(1)(即,常量)内存解决此问题

方法一:哈希表:时间复杂度:O(N) 空间复杂度:O(N)

/**
 * Definition for singly-linked list.
 * class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    public boolean hasCycle(ListNode head) {
        //HashSet存储的是对象,即使val相等,指针地址也不相同
        Set<ListNode> seen = new HashSet<ListNode>();
        while (head != null) {
            //.add()不能添加重复数据,所以当出现重复数据时是false,!使其成为ture。
            //说明存在重复节点,返回true
            if (!seen.add(head)) {
                return true;
            }
            head = head.next;
        }
        return false;
    }
}
方法二:快慢指针:时间复杂度:O(N) 空间复杂度:O(1)

本方法需要读者对「Floyd 判圈算法」(又称龟兔赛跑算法)有所了解。
在这里插入图片描述

来源:
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/linked-list-cycle/solution/huan-xing-lian-biao-by-leetcode-solution/
在这里插入图片描述

public class Solution {
    public boolean hasCycle(ListNode head) {
        if (head == null || head.next == null) {
            return false;
        }
        ListNode slow = head;
        ListNode fast = head.next;
        while (slow != fast) {
            if (fast == null || fast.next == null) {
                return false;
            }
            slow = slow.next;
            fast = fast.next.next;
        }
        return true;
    }
}

234、难度简单:

要求:用 O(n) 时间复杂度和 O(1) 空间复杂度解决此题
参考来源:
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/palindrome-linked-list/solution/hui-wen-lian-biao-by-leetcode-solution/

方法一:将值复制到数组中后用双指针法:时空复杂度:O(n)
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    private ListNode frontPointer;

    private boolean recursivelyCheck(ListNode currentNode) {
        if (currentNode != null) {
            if (!recursivelyCheck(currentNode.next)) {
                return false;
            }
            if (currentNode.val != frontPointer.val) {
                return false;
            }
            frontPointer = frontPointer.next;
        }
        return true;
    }

    public boolean isPalindrome(ListNode head) {
        frontPointer = head;
        return recursivelyCheck(head);
    }
}

思路:
1、复制链表值到数组列表中、使用双指针法判断是否为回文;
2、先遍历链表将值赋值到数组列表中、使用双指针法来检查是否为回文。我们在起点放置一个指针,在结尾放置一个指针,每一次迭代判断两个指针指向的元素是否相同,若不同,返回 false;相同则将两个指针向内移动,并继续判断,直到两个指针相遇
在这里插入图片描述

方法二:递归:时空复杂度O(n):该方法比方法一效果更差

为了想出使用空间复杂度为 O(1)O(1) 的算法,你可能想过使用递归来解决,但是这仍然需要 O(n)O(n) 的空间复杂度。
使用递归反向迭代节点,同时使用递归函数外的变量向前迭代,就可以判断链表是否为回文。

算法:
在这里插入图片描述

class Solution {
    //首指针
    private ListNode frontPointer;

    private boolean recursivelyCheck(ListNode currentNode) {
        //当前指针不为空,也就是未达到末尾节点就继续执行
        if (currentNode != null) {
            //开始递归,调用自身。当上一次调用返回false(前后节点不相等时)时!起到true的作用,返回false
            //但是该if判断没执行一次就会调用自己一次,让当前指针一直后移,直到当前节点为末尾节点为止,上面的if判断不成立
            //返回true,才正式开始走下面的if判断首尾是否相等
            if (!recursivelyCheck(currentNode.next)) {
                return false;
            }
            if (currentNode.val != frontPointer.val) {
                return false;
            }
            //由于上一行的if判断过了,说明首尾相同,所以 前指针后移一位
            frontPointer = frontPointer.next;
        }
        //每一次判断首尾相等成功,就返回true,继续判断下两个节点
        return true;
    }
	//从调用该方法开始
    public boolean isPalindrome(ListNode head) {
        //递归外的部分,只执行一次
        frontPointer = head;
        //调用递归,返回最终结果
        return recursivelyCheck(head);
    }
}
方法三:快慢指针:时间复杂度:O(n) 空间复杂度:O(1)
class Solution {
    public boolean isPalindrome(ListNode head) {
        if (head == null) {
            return true;
        }

        // 找到前半部分链表的尾节点并反转后半部分链表
        ListNode firstHalfEnd = endOfFirstHalf(head);
        ListNode secondHalfStart = reverseList(firstHalfEnd.next);

        // 判断是否回文
        ListNode p1 = head;
        ListNode p2 = secondHalfStart;
        boolean result = true;
        while (result && p2 != null) {
            if (p1.val != p2.val) {
                result = false;
            }
            p1 = p1.next;
            p2 = p2.next;
        }        

        // 还原链表并返回结果
        firstHalfEnd.next = reverseList(secondHalfStart);
        return result;
    }
    
	//反转链表
    private ListNode reverseList(ListNode head) {
        ListNode prev = null;
        ListNode curr = head;
        while (curr != null) {
            ListNode nextTemp = curr.next;
            curr.next = prev;
            prev = curr;
            curr = nextTemp;
        }
        return prev;
    }
	//找到前半部分链表的尾节点:快慢指针
    private ListNode endOfFirstHalf(ListNode head) {
        ListNode fast = head;
        ListNode slow = head;
        while (fast.next != null && fast.next.next != null) {
            fast = fast.next.next;
            slow = slow.next;
        }
        return slow;
    }
}

原理:
在这里插入图片描述

解题过程:
在这里插入图片描述

将执行用时、内存消耗极大提高的另一种写法:(缺陷:破坏了链表结构)

public boolean isPalindrome(ListNode head) {
    if(head == null || head.next == null) {
        return true;
    }
    ListNode slow = head, fast = head;
    ListNode pre = head, prepre = null;
    //快慢指针,slow走到一半、fast走完全程时停止循环
    while(fast != null && fast.next != null) {
        pre = slow;
        slow = slow.next;
        fast = fast.next.next;
        pre.next = prepre;
        prepre = pre;
    }
    //处理链表个数为奇数的情况
    if(fast != null) {
        slow = slow.next;
    }
    while(pre != null && slow != null) {
        //pre作为前半链表反转后的头节点
        if(pre.val != slow.val) {
            return false;
        }
        pre = pre.next;
        slow = slow.next;
    }
    return true;
}
//作者:nuan
//链接:https://leetcode-cn.com/problems/palindrome-linked-list/solution/wo-de-kuai-man-zhi-zhen-du-cong-tou-kai-shi-gan-ju/

快指针走到末尾,慢指针刚好到中间。其中慢指针将前半部分反转。然后比较
快慢指针找链表中间结点的同时,慢指针将其扫过的链表部分进行反转,再从中间对比。
pre和prepre用于反转链表。slow和fast分别用于走一半和走全程:

这里依次记录下 while(fast != null && fast.next != null) 循环中各变量的值更替
pre = slow;            0         1            同理
slow = slow.next;      1         2 
fast = fast.next.next; 2 	     4	
pre.next = prepre;     0->null   1->0->null
prepre = pre;          0->null   1->0->null
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CodeYello

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值