20230914刷题记录
参考【代码随想录】来刷的。
关键词:链表、环形链表、哈希表
1 链表相交
面试题 02.07. 链表相交
力扣题目链接
easy
用于遍历长度较长的那个链表的指针要先移动。
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
int lengthA = 0;
int lengthB = 0;
ListNode p = headA;
ListNode q = headB;
while (p != null) {
++lengthA;
p = p.next;
}
while (q != null) {
++lengthB;
q = q.next;
}
p = headA;
q = headB;
if (lengthA > lengthB)
for (int i = 0; i < (lengthA - lengthB); i++)
p = p.next;
else
for (int i = 0; i < (lengthB - lengthA); i++)
q = q.next;
while (p != null) {
if (p == q)
return p;
p = p.next;
q = q.next;
}
return null;
}
}
2 环形链表II
142.环形链表II
力扣题目链接
可以分解为两个问题:
- 是否存在环
- 找到环入口
2.1 是否存在环
使用快慢指针,slow、fast,slow一次移动一个结点,fast一次移动两个结点。
如果移动数次后,fast为空,那么不存在环。
如果slow与fast相遇,那么存在环。
2.2 找到环入口
假设从头结点到环形入口节点 的节点数为x。
环形入口节点到 fast指针与slow指针相遇节点 节点数为y。
从相遇节点 再到环形入口节点节点数为 z。
相遇时,
慢指针走过的结点数为
S
s
l
o
w
=
x
+
m
(
y
+
z
)
+
y
Sslow=x+m(y+z)+y
Sslow=x+m(y+z)+y
其中m为快慢指针相遇时,慢指针走过的环的圈数。
快指针走过的结点数为
S
f
a
s
t
=
x
+
n
(
y
+
z
)
+
y
Sfast=x+n(y+z)+y
Sfast=x+n(y+z)+y
其中n为快慢指针相遇时,快指针走过的环的圈数。
又快指针的速度是慢指针速度的两倍,花费的时间相同,故
S
f
a
s
t
=
2
S
s
l
o
w
Sfast=2Sslow
Sfast=2Sslow
即
x
+
n
(
y
+
z
)
+
y
=
2
(
x
+
m
(
y
+
z
)
+
y
)
x+n(y+z)+y = 2(x+m(y+z)+y)
x+n(y+z)+y=2(x+m(y+z)+y)
化简得
x
=
(
n
−
2
m
)
(
y
+
z
)
−
y
x=(n-2m)(y+z)-y
x=(n−2m)(y+z)−y
将x带入
S
s
l
o
w
=
x
+
m
(
y
+
z
)
+
y
Sslow=x+m(y+z)+y
Sslow=x+m(y+z)+y
得
S
s
l
o
w
=
(
n
−
m
)
(
y
+
z
)
Sslow=(n-m)(y+z)
Sslow=(n−m)(y+z)
即当快慢指针相遇时,慢指针移动的总结点数为上式。
又慢指针移动的总结点数=慢指针在环外移动的结点数+慢指针在环内移动的结点数。
故快慢指针相遇时,慢指针在环内移动的结点数为
(
n
−
m
)
(
y
+
z
)
−
x
(n-m)(y+z)-x
(n−m)(y+z)−x
即慢指针再移动 x 个结点即可到达环入口。
因为再移动 x 个结点后,慢指针在环内移动的结点数为
(
n
−
m
)
(
y
+
z
)
,
(n-m)(y+z),
(n−m)(y+z),
即为环内结点数的整数倍。
故可让fast指向链表的头结点,让fast与slow同时开始移动,且fast与slow每次均移动一个结点,则fast必定会与slow在环入口处相遇。
public class Solution {
public ListNode detectCycle(ListNode head) {
ListNode slow = head;
ListNode fast = head;
try {
do {
fast = fast.next.next;
slow = slow.next;
} while (fast != slow);
} catch (NullPointerException e) {
return null;
}
fast = head;
while (fast != slow) {
fast = fast.next;
slow = slow.next;
}
return slow;
}
}
3 有效的字母异位词
242.有效的字母异位词
力扣题目链接
给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。
如果 t 与 s 互为字母异位词,那么 t 中字母的出现次数必定与 s 中的相同。
可以用哈希表来记录每个字母的出现次数,因为从哈希表中取数据的操作是O(1)。
哈希表有两种实现方式:
- java自带的hash表,HashSet、HashMap
- 自己用数组实现
直接使用set 不仅占用空间比数组大,而且速度要比数组慢,set把数值映射到key上都要做hash计算的。
不要小瞧 这个耗时,在数据量大的情况,差距是很明显的。
优点 | 缺点 | |
---|---|---|
自带 | 实现方便 | 速度比数组慢 |
用数组实现 | 速度更快 | 必须知道数组的长度,即最大数据的值 |
class Solution {
public boolean isAnagram(String s, String t) {
int[] record = new int[26];
for (int i = 0; i < s.length(); i++) {
record[s.charAt(i) - 'a']++;
}
for (int i = 0; i < t.length(); i++) {
record[t.charAt(i) - 'a']--;
}
for (int i = 0; i < record.length; i++) {
if (record[i] != 0)
return false;
}
return true;
}
}
4 两个数组的交集
349.两个数组的交集
力扣题目链接
步骤
- 将nums1中的数据存入hash1
- 遍历nums2,如果nums2中的数据也在hash1中,则将该数据存入hash2
- 遍历hash2,将符合条件的加入list
- 将list转为数组
注意将list转为数组的处理方式。
class Solution {
public int[] intersection(int[] nums1, int[] nums2) {
int[] hash1 = new int[1001];
int[] hash2 = new int[1001];
for (int n1: nums1) {
hash1[n1] = 1;
}
for (int n2: nums2) {
if (hash1[n2] == 1)
hash2[n2] = 1;
}
List<Integer> resList = new ArrayList<>();
for (int i = 0; i < hash2.length; i++) {
if (hash2[i] > 0)
resList.add(i);
}
return resList.stream().mapToInt(item -> item).toArray();
}
}
5 两个数组的交集 II
350.两个数组的交集 II
力扣题目链接
跟上面的类似。
class Solution {
public int[] intersect(int[] nums1, int[] nums2) {
int[] hash1 = new int[1001];
int[] hash2 = new int[1001];
for (int n1: nums1)
hash1[n1]++;
for (int n2: nums2)
hash2[n2]++;
List<Integer> reList = new ArrayList<>();
for (int i = 0; i < hash1.length; i++) {
if (hash1[i] > 0 && hash2[i] > 0)
for (int i1 = 0; i1 < Math.min(hash1[i], hash2[i]); i1++)
reList.add(i);
}
return reList.stream().mapToInt(x -> x).toArray();
}
}
6 快乐数
力扣题目链接
两点
- 如何找出重复的结果?
使用哈希表,取数据操作的时间复杂度为O(1)。 - 如何对int型数据的每一个进行处理?
取余。
class Solution {
public boolean isHappy(int n) {
Set<Integer> set = new HashSet<>();
while (n != 1 && !set.contains(n)) {
set.add(n);
n = getNextNumber(n);
}
return n == 1;
}
private int getNextNumber(int n) {
int res = 0;
while (n != 0) {
int temp = n % 10;
res += temp * temp;
n /= 10;
}
return res;
}
}