环形链表 II
给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。
不允许修改 链表。
![](https://i-blog.csdnimg.cn/blog_migrate/1d228583fadd8c97ea774e3a2b4b57a6.png)
题解:关于环形链表的题目,我们首先要判断这个链表里面有没有环,然后再来判断入环的节点是在哪里
首先谈谈如何判断这个链表里面有没有环,思路是设计快慢指针来进行判断这个链表是否有环
那么将快指针设计成每次走两个步长,慢指针每次走一个步长,假设链表有环那么在环里面快慢指针一定会相遇,假设没有环的话快指针就会指向null
为什么一定要将快指针设计成每次走两个步长,慢指针每次走一个步长呢,因为这样设计的话,那么慢指针进入到环中,两个指针会一直在圈里面转,那么快指针一定会在环里面追上慢指针并且和慢指针相遇,因为快指针每次走两个步长,慢指针每次走一个步长,那么以慢指针为参考系,快指针就是相对于自己每次走一个步长,那么两个指针一定会相遇。假设快指针设计成走其他的步长,那么极有可能快指针会错过慢指针,比如我将快指针设计成每次走三个步长,那么还是以慢指针为参考系,快指针相对于慢指针每次就是走两个步长,那么也就意味着快指针每次会跳过一个节点走到下一个节点。假设两个指针相遇了,那么也就证明这个链表里面是有环的
![](https://i-blog.csdnimg.cn/blog_migrate/dccfaedcad1032f64c9422de33c5b509.png)
那么再来讨论如何找到节点的入口
我们首先要知道快指针在慢指针走的第一圈里面就可以和慢指针相遇
我们画一个图就可以很好的证明,假设我们将这个环铺开成一条直线,那么由于步长不同,那么在相同的时间里面,快指针走的路程是慢指针的两倍
![](https://i-blog.csdnimg.cn/blog_migrate/f6a6139893db264dd9f312197c4a8690.png)
我们通过fast 和slow两个指针所走过的长度进行数学推到我们最终的到这么一个等式
这也就是说当慢指针进入环中的时候快指针起码走了一圈
当我们把n设成1的时候,那么x和z就相等了,也就是说我们同时设两个指针一个指向起点一个指向相遇点,同时开始走,那么相遇的地方就是环的入口
当然如果我们的n并不设成1结果也还是一样的,当我们指向相遇点的指针走了n-1圈以后还是回到了相遇点,这个时候只要走到了入口处(走完z的路程)就回到了入口,这个时候从起点出发的指针也刚好走到入口处,两个指针相遇
最后有了思路再贴上我们的完整代码
public ListNode detectCycle(ListNode head) {
ListNode dummyhead = new ListNode(0);
dummyhead.next = head;
ListNode fast = dummyhead;
ListNode slow = dummyhead;
while(fast != null && fast.next != null){
fast = fast.next.next;
slow = slow.next;
if(fast == slow){
break;
}
}
if(fast == slow && fast.next != null){
ListNode cur1 = dummyhead;
ListNode cur2 = fast;
while(cur1 != cur2 && cur1 != null && cur2 != null){
cur1 = cur1.next;
cur2 = cur2.next;
}
return cur1;
}
return null;
}
有效的字母异位词
给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。
注意:若 s 和 t 中每个字符出现的次数都相同,则称 s 和 t 互为字母异位词。
示例 1:
输入:s = "anagram", t = "nagaram"
输出: true
示例 2:
输入:s = "rat", t = "car"
输出: false
题解:当我们看到出现的次数的时候我们应该想到使用哈希表的思路来进行解决这种问题
这里我们使用数组来解决这种问题,我们使用一个数组来记录每个字符串里面字母出现的次数是多少,当我们统计第一组字符串的时候,统一给出现的字母所对应的索引加上1。当我们统计第二组字符串的时候,同一给出现字母所对应的索引减去1,最后当整个数组里面的索引都是0的话,那么这两个字符串就是题目所要求的字符串
最后贴上我们的代码
public boolean isAnagram(String s, String t) {
if(s.length() != t.length()){
return false;
}
int[] array = new int[26];
for(int i = 0;i < s.length();i++){
array[s.charAt(i) - 'a']++;
}
for(int i = 0;i < t.length();i++){
array[t.charAt(i) - 'a']--;
if(array[t.charAt(i) - 'a'] < 0){
return false;
}
}
两个数组的交集
给定两个数组 nums1 和 nums2 ,返回 它们的交集 。输出结果中的每个元素一定是 唯一 的。我们可以 不考虑输出结果的顺序 。
示例 1:
输入:nums1 = [1,2,2,1], nums2 = [2,2]
输出:[2]
示例 2:
输入:nums1 = [4,9,5], nums2 = [9,4,9,8,4]
输出:[9,4]
解释:[4,9] 也是可通过的
题解:看到唯一我们就应该想到使用哈希表的思路来解决这道题目,由于这里要求元素是唯一的,那么我们就是HashSet的思路来解决这道题目
由于我们只需要返回交集,所以我们使用Set就可以将数组里面的元素进行去重操作,所以我们创建两个HashSet来装填我们数组里面的元素,当我们创建完两个Set之后我们再创建一个Set来添加找到两个Set的交集元素,由于我们最后是要返回一个数组,所以我们要创建一个新数组然后使用迭代器将我们Set里面的数据遍历的同时添加到我们的数组里面去
最后贴上完整代码
HashSet<Integer> set1 = new HashSet<Integer>();
HashSet<Integer> set2 = new HashSet<Integer>();
for(int i = 0;i < nums1.length;i++){
set1.add(nums1[i]);
}
for(int i = 0;i < nums2.length;i++){
set2.add(nums2[i]);
}
int[] arr = new int[1000];
for(Integer a:set1){
arr[a]++;
}
for(Integer a:set2){
arr[a]++;
}
int length = 0;
int a = 0;
for(int i = 0;i < arr.length;i++){
if(arr[i] >= 2){
length++;
}
}
int[] num = new int[length];
for(int i = 0;i < arr.length;i++){
if(arr[i] >= 2){
num[a] = i;
a++;
}
}
return num;
}