142.环形链表II
2 ( x + y ) = x + y + n ( y + z ) / / 快慢指针步数等式 ( 1 ) 2(x+y)=x+y+n(y+z) //快慢指针步数等式(1) 2(x+y)=x+y+n(y+z)//快慢指针步数等式(1)
x = ( n − 1 ) ( y + z ) + z / / 其中 n ≥ 1 ,其中 y + z 为整周,可忽略 ( 2 ) x=(n-1)(y+z)+z //其中n≥1,其中y+z为整周,可忽略(2) x=(n−1)(y+z)+z//其中n≥1,其中y+z为整周,可忽略(2)
问题:为什么公式(1)左侧慢指针不是走过n圈,默认走过一圈?
答:慢指针进入环中时,快指针是慢指针速度的两倍,那么快指针一定会追上慢指针,此时相遇
//快慢指针法
public class Solution {
public ListNode detectCycle(ListNode head) {
ListNode fast = head;
ListNode slow = head;
while(fast != null && fast.next != null){
slow = slow.next;
fast = fast.next.next;
//首先找到快慢指针相遇的点
if(slow == fast){
ListNode temp1 = fast;
ListNode temp2 = head;
//根据公式2编写,确定出x的长度
while(temp1 != temp2){
temp1 = temp1.next;
temp2 = temp2.next;
}
return temp1;
}
}
//没有环路退出
return null;
}
}
哈希表基础知识
✨索引—>元素,查询时使用哈希表结构则时间复杂度为O(1)
哈希函数:用于映射元素与索引的关系,当索引大于哈希表的大小的时候,就要对哈希表做取模操作
哈希碰撞概念:使用哈希函数是不同元素得到的哈希值相同
哈希碰撞解决方法:使用拉链法或者线性探测法
拉链法:
线性探测法:
🌏哈希法的应用场景:当我们遇到了要快速判断一个元素是否出现集合里的时候,就要考虑哈希法。
哈希法缺点:牺牲了空间换取了时间,因为我们要使用额外的数组,set或者是map来存放数据,才能实现快速的查找。
242.有效的字母异位词
哈希表:
//额外创建一个数组作为哈希表存储每个字母出现的额频率
//关键设置:创建个数哈希表eachLetterNum s.charAt(i)-'a'设置每个字母下标一一对应
class Solution {
public boolean isAnagram(String s, String t) {
//数组就是哈希表
int[] eachLetterNum = new int[26];
for(int i=0; i<s.length(); i++){
eachLetterNum[s.charAt(i)-'a']++;
}
for(int i=0; i<t.length(); i++){
eachLetterNum[t.charAt(i)-'a']--;
}
//当数组中的元素都等于0时说明此时两个字符串的元素完全一致
for(int i=0; i<26; i++){
if(eachLetterNum[i]!=0){
return false;
}
}
return true;
}
}
349. 两个数组的交集
//哈希表法
class Solution {
public int[] intersection(int[] nums1, int[] nums2) {
Set<Integer> set1 = new HashSet<>();
Set<Integer> resSet = new HashSet<>();
if(nums1==null && nums1.length==0 && nums2==null && nums2.length==0) return null;
for(int i:nums1){
set1.add(i);
}
for(int i:nums2){
if(set1.contains(i)){
resSet.add(i);
}
}
int j = 0;
int[] arr = new int[resSet.size()];
for(int i:resSet){
arr[j++] = i;
}
return arr;
}
}
//数组法
//因为数值的区间为0到1000,所以可以采用数组法
class Solution {
public int[] intersection(int[] nums1, int[] nums2) {
int[] numOfEachNumber = new int[1001];
Set<Integer> resSet = new HashSet<>();
for(int i:nums1){
numOfEachNumber[i] = 1;
}
for(int i:nums2){
if(numOfEachNumber[i] == 1){
resSet.add(i);
}
}
int j = 0;
int[] resArr = new int[resSet.size()];
for(int i:resSet){
resArr[j++] = i;
}
return resArr;
}
}
第202题. 快乐数
class Solution {
public boolean isHappy(int n) {
Set<Integer> set1 = new HashSet<>();
while(n!=1 && !set1.contains(n)){
set1.add(n);
n = getNumberSum(n);
}
return n==1;
}
//这个函数的作用为将每一位拆开,平方后再加起来
public int getNumberSum(int n){
int res = 0;
while(n>0){
int temp = n%10;
res += temp*temp;
n = n/10;
}
return res;
}
}
问题:为什么sum重复时就认为这不是一个快乐数?
答:因为当出现一次sum重复时,sum会一直循环下去(循环退出的关键条件)
1. 两数之和
//暴力解法
class Solution {
public int[] twoSum(int[] nums, int target) {
int[] arr = new int[2];
for(int j=0; j<nums.length; j++){
for(int i=j+1; i<nums.length; i++){
if((nums[j]+nums[i]) == target){
arr[0] = j;
arr[1] = i;
}
}
}
return arr;
}
}
//使用HashMap
class Solution {
public int[] twoSum(int[] nums, int target) {
//用于存放返回的下标
int[] arr = new int[2];
Map<Integer,Integer> map1 = new HashMap<>();
for(int i=0; i<nums.length; i++){
if(map1.containsKey(target-nums[i])){
arr[0] = i;
arr[1] = map1.get(target-nums[i]);
return arr;
}
//要把向Map中添加元素的语句放到判断之后,防止自己和自己相加
map1.put(nums[i],i);
}
return null;
}
}