文章目录
前言
今天是寒假LeetCode刷题打卡的第十一天,继续坚持、继续加油!也希望我的博文能够帮助到大家,若有疑问,可以随时私信Call我!
在今天的题目中,第一题使用到了异或的思想;第二题和第三题则是使用到快慢指针的思想。
一、136 只出现一次的数字
1. 题目描述
题号:136
难度:简单
136 只出现一次的数字
给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
说明:
你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?
示例 1:
输入: [2,2,1]
输出: 1
示例 2:
输入: [4,1,2,1,2]
输出: 4
2. 解题思路
我先是自己想了一种方法,鉴于我看题解之后发现没有与我的方法相同的,因此在代码实现中的方法一我会附上按照我之前自己的想法写的代码。
方法一的思路是:将重复的位置置为Integer.MAX_VALUE这一数组中不可能存在的特殊值。然后依次向后遍历,当相等时置为INT的最大值;当不等时,改变i,j,进入下一次循环。若为特殊值,则继续进入下一循环。
方法二的基本思想是:使用异或。这里引入异或的三个基本性质。
任何数和 00 做异或运算,结果仍然是原来的数,即 a ⊕ 0=a⊕0=a;
任何数和其自身做异或运算,结果是 0,即 a ⊕ a=0;
异或运算满足交换律和结合律,即 a ⊕ b ⊕ a=b ⊕ a ⊕ a=b ⊕ (a ⊕ a)=b ⊕0=b。
因此,若输入的数组符合题目要求,则结果(只出现一次的那个数字)等于初始为0的一个变量与每个元素分别进行异或后的值。
3. 代码实现
方法一:
class Solution {
public int singleNumber(int[] nums) {
int i=0,j=1;
while(i<nums.length&&j<nums.length)
{
if(nums[i]==Integer.MAX_VALUE)
{
++i;
j=i+1;
}
else if(nums[i]==nums[j])
{
nums[i]=Integer.MAX_VALUE;
nums[j]=Integer.MAX_VALUE;
++i;
j=i+1;
}
else
{
++j;
}
if(j==nums.length)
return nums[i];
}
return nums[0];
}
}
方法二:
class Solution {
public int singleNumber(int[] nums) {
int single = 0;
for (int num : nums) {
single ^= num;
}
return single;
}
}
二、141 环形链表
1. 题目描述
题号:141
难度:简单
141 环形链表
给定一个链表,判断链表中是否有环。
为了表示给定链表中的环,我们使用整数pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果pos是 -1,则在该链表中没有环。
示例 1:
输入:head = [3,2,0,-4], pos = 1
输出:true
解释:链表中有一个环,其尾部连接到第二个节点。
示例 2:
输入:head = [1,2], pos = 0
输出:true
解释:链表中有一个环,其尾部连接到第一个节点。
示例 3:
输入:head = [1], pos = -1
输出:false
解释:链表中没有环。
进阶:
你能用 O(1)(即,常量)内存解决此问题吗?
2. 解题思路
如果没有O(1)内存的要求,则可以使用hash。但是本题要求空间复杂度为O(1)。
因此我们采用快慢指针来实现此题。设置一个快指针和慢指针。两种情况:
1、若没有环,则慢指针永远追不上快指针,最后会循环到最后一个位置,然后结束循环,返回false。
2、若有环,则慢指针终有一个时候能够追上快指针,若追上,则返回true。
3. 代码实现
具体代码如下:
public boolean hasCycle(ListNode head) {
if(head==null||head.next==null)
return false;
ListNode slow=head;
ListNode fast=head.next;
while(slow!=fast&&fast!=null&&fast.next!=null)
{
slow=slow.next;
fast=fast.next.next;
}
if(slow==fast)
return true;
return false;
}
三、142 环形链表 II
1. 题目描述
题号:142
难度:中等
142 环形链表 II
给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。
说明:不允许修改给定的链表。
示例 1:
输入:head = [3,2,0,-4], pos = 1
输出:tail connects to node index 1
解释:链表中有一个环,其尾部连接到第二个节点。
示例 2:
输入:head = [1,2], pos = 0
输出:tail connects to node index 0
解释:链表中有一个环,其尾部连接到第一个节点。
示例 3:
输入:head = [1], pos = -1
输出:no cycle
解释:链表中没有环。
进阶:
你是否可以不用额外空间解决此题?
2. 解题思路
我的思路是首先略为修改上一题的方法,找到slow与fast相等的那个节点。但是此节点并不一定是pos节点。然后我通过观察链表,想到=此节点必定处于环中,然后我们利用这一特点,将环中的所有节点的next置为null。然后,从head开始往后遍历,等于null的前一个节点即是我们要找的环的首节点。时间复杂度和空间复杂度均符合进阶中的要求。
官方题解的思路也是双指针,但是在具体实现中与我的思路有所不同,具体可参考 环形链表 II 官方题解
由于我的思路与官方题解有所差异,因此在下面的代码实现中,我将两个思路的代码实现都附上。方法一是我的方法,方法二是官方题解的方法。
3. 代码实现
方法一:
public class Solution {
public ListNode detectCycle(ListNode head) {
ListNode cycle=hasCycle(head);
if(cycle==null)
return null;
ListNode i=cycle;
ListNode j=cycle.next;
while(i.next!=null)
{
i.next=null;
i=j;
j=j.next;
}
while(head.next!=null)
{
head=head.next;
}
return head;
}
public ListNode hasCycle(ListNode head) {
if(head==null||head.next==null)
return null;
ListNode slow=head;
ListNode fast=head.next;
while(slow!=fast&&fast!=null&&fast.next!=null)
{
slow=slow.next;
fast=fast.next.next;
}
if(slow==fast)
return slow;
return null;
}
}
方法二:
public class Solution {
public ListNode detectCycle(ListNode head) {
if (head == null) {
return null;
}
ListNode slow = head, fast = head;
while (fast != null) {
slow = slow.next;
if (fast.next != null) {
fast = fast.next.next;
} else {
return null;
}
if (fast == slow) {
ListNode ptr = head;
while (ptr != slow) {
ptr = ptr.next;
slow = slow.next;
}
return ptr;
}
}
return null;
}
}
总结
以上就是今天 LeetCode寒假刷题 Day11 所做的三道题。若有任何疑问,欢迎私信或评论区留言鸭!