链表
- 双指针法
纯纯数学题。
第一步,判断链表是否有环。一个fast指针一个slow指针,fast指针一次走两步,slow指针走一步,如果没环,slow指针就先走完了,如果有环,fast指针肯定和slow指针相遇在环中,并且此时fast指针多绕了n圈环。
第二步,有环找入口。从头结点到环形入口节点 的节点数为x。 环形入口节点到 fast指针与slow指针相遇节点 节点数为y。 从相遇节点 再到环形入口节点节点数为 z。
fast指针走的距离为
x + y + n (y + z),slow指针走的距离为x + y,因为fast指针是一步走两个节点,slow指针一步走一个节点, 所以fast走的距离是slow的两倍可得到等式:(x + y) * 2 = x + y + n (y + z)化简得到x + y = n (y + z)要找环形的入口,即求x可得
x = n (y + z) - y。整理公式之后为如下公式:
x = (n - 1) (y + z) + z。y + z就是环节点数,n=1时,x = z,解题思路就是从头结点出发一个指针,从相遇节点也出发一个指针,这两个指针每次只走一个节点, 那么当这两个指针相遇的时候就是 环形入口的节点。n>1时,其实效果一样,脑内可以过一遍。
public class Solution {
public ListNode detectCycle(ListNode head) {
ListNode fast =head;//快指针
ListNode slow =head;//慢指针
while(fast!=null&&fast.next!=null){//快指针能走得完则无环
fast=fast.next.next;//快指针走两步
slow=slow.next;//慢指针走一步
if(fast==slow){//第一次相遇,则说明有环
fast=head;//重新定义了一个头结点,
while(fast!=slow){//再次相遇点就是入环点
fast=fast.next;
slow=slow.next;
}
return fast;
}
}
return null;
}
}
哈希表
- 方法一:暴力
class Solution {
public int[] twoSum(int[] nums, int target) {
int[] arr=new int[2];
for(int i=0;i<nums.length-1;i++){
for(int j=i+1;j<nums.length;j++){
if(nums[i]+nums[j]==target){
arr[0]=i;arr[1]=j;
return arr;
}
}
}
return null;
}
}
- 方法二:哈希表
遍历数组 nums,i 为当前下标,每个值都判断map中是否存在 target-nums[i] 的 key 值
如果存在则找到了两个值,如果不存在则将当前的 (nums[i],i) 存入 map 中,继续遍历直到找到为止
class Solution {
public int[] twoSum(int[] nums, int target) {
Map<Integer, Integer> map=new HashMap<>();//哈希表里,key是元素,value是下标
for(int i=0;i<nums.length;i++){
if(map.containsKey(target-nums[i])){//查看map里面是否存在 target-nums[i] 的 key 值
int[] arr={map.get(target-nums[i]), i};//存在就返回value(value存的是数组下标),注意这个顺序,当前是i,另一个元素的下标必定存在前面
return arr;
}
map.put(nums[i],i);//没有就把当前num[i]存入map
}
return null;
}
}