leetcode
leetcode-141-环形链表
题目大意:给定一个链表,判断该链表是存在环;
1、快慢指针
-
设定一个快指针,一个慢指针。
-
若有环,且慢指针在环外,快指针出不去,将一直在环中循环,直到慢指针入环,被快指针追上,相遇;
-
若无环,快指针将到达链表尾部;
public class Solution {
public boolean hasCycle(ListNode head) {
if(head == null || head.next == null)return false;
ListNode fast = head;
ListNode slow = head;
while(fast != null && fast.next != null){
fast = fast.next.next;
slow = slow.next;
if(fast == slow)return true;
}
return false;
}
}
2、哈希 set
- 若有环,环内节点会走到两次或以上;
public class Solution {
public boolean hasCycle(ListNode head) {
if(head == null || head.next == null)return false;
Set<ListNode> set = new HashSet<>();
while(head != null){
if(set.add(head));
else return true;
head = head.next;
}
return false;
}
}
leetcode-160-相交链表
题目大意:找到两个链表的相交的起始节点
此节点为 c1;
1、 暴力解法
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
if(headA == null || headB == null)return null;
for(ListNode la = headA; la != null; la = la.next){
for(ListNode lb = headB; lb != null; lb = lb.next){
if(la == lb)return la;
}
}
return null;
}
}
2、 双指针
-
a = a 非共同部分的长度,
-
b = b 非共同部分的长度
-
all =共同部分的长度
-
故 a+b+all = b+a=all
-
则可用双指针,当指针 a 循环完 a 链表则调到 b 链表首,当 a 第二次经过共同部分时,b 肯定也恰好到达共同部分;
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
if(headA == null || headB == null)return null;
ListNode la = headA,lb = headB;
boolean f = false;
while(la != null){
if(la == lb)return la;
la = la.next;
lb = lb.next;
if(la == null && !f){
f = !f;
la = headB;
}
if(lb == null)lb = headA;
}
return null;
}
}
leetcode-203-移除链表
题意:删除链表中的一个值;
ps:我的思路简单循环即可,但是自己的代码很蠢;
class Solution {
public ListNode removeElements(ListNode head, int val) {
while(head != null && head.val == val )head = head.next;
if(head == null)return null;
ListNode q, pre = head;//可以只用p.next省略掉麻烦的pre;
if(head.next != null) q = head.next;
else return head;
while(q != null){
if(q.val == val){//如果此节点要删除,则pre节点不动;
pre.next = q.next;
q = q.next;
}
else{
pre = q;
q = q.next;
}
}
return head;
}
}
用 q.next 代替 q, q 代替 pre;少写一个 pre,代码简介易懂,还不麻烦;
class Solution {
public ListNode removeElements(ListNode head, int val) {
while(head != null && head.val == val )head = head.next;
if(head == null)return null;
ListNode q = head;
while(q.next != null){
if(q.next.val == val){
q.next = q.next.next;
}
else{
q = q.next;
}
}
return head;
}
}
递归做法,现在对递归的掌握还没熟练的应用进各个习题,对每个题目的第一个反应就是暴力,自己很愚蠢,总学不会(哪有总是学,天天玩。分明就是自己不刷题),慢慢来吧;
class Solution {
public ListNode removeElements(ListNode head, int val) {
if(head == null)return null;
head.next = removeElements(head.next,val);//通过该函数的返回值,一个个连起来;
if(head.val == val)return head.next;
return head;
}
}
leetcode-206-反转链表
示例:
**输入**: 1->2->3->4->5->NULL
**输出**: 5->4->3->2->1->NULL
愚蠢的我,还是不会做递归
class Solution {
public ListNode reverseList(ListNode head) {
if(head == null)return null;
ListNode prev = null, curr = head;
while(curr != null){
ListNode temp = curr.next;
curr.next = prev;
prev = curr;
curr = temp;
}
return prev;
}
}
2、递归
leetcode 官方题解:
假设列表为:
n1→…→ nk−1 → nk → nk+1 →…→ nm → ∅
节点 nm - nk+1 已经反转,我们在 nk 位置;
n1 →…→ nk−1 → nk → nk+1 ←…← nm
我们希望 nk+1 的下一个节点指向 nk。
所以,nk.next.next = nk。
要小心的是 n1 的下一个必须指向 Ø 。如果你忽略了这一点,你的链表中可能会产生循环。如果使用大小为 2 的链表测试代码,则可能会捕获此错误。
刚学的递归,这题又没想出来。想到用递归,确不知道怎么做
class Solution {
public ListNode reverseList(ListNode head) {
if(head == null || head.next == null)return head;
ListNode p = reverseList(head.next);
head.next.next = head;
head.next = null;
return p;
}
}
leetcode-234-回文链表
**示例 1:
输入: 1->2
输出: false
输入: 1->2->2->1
输出: true
双指针牛批大法:
利用快慢指针,将前半段反转;
class Solution {
public boolean isPalindrome(ListNode head) {
if(head == null || head.next == null)return true;
ListNode fast = head,slow = head;
ListNode pre = head, prepre = null;
while(fast != null && fast.next != null){
pre = slow;
slow = slow.next;
fast = fast.next.next;
pre.next = prepre;
prepre = pre;
}
if(fast != null)slow = slow.next;//当为奇数时,跳过中间的数;
while(pre != null && slow != null){
if(pre.val != slow.val)return false;
pre = pre.next;
slow = slow.next;
}
return true;
}
}
leetcode-876-链表的中间节点
题意:
删除链表的中间节点,当为偶数数时,删除第二个中间节点;
ps:利用上一道题的快慢指针很好做,正好学到;
class Solution {
public ListNode middleNode(ListNode head) {
ListNode fast = head,slow = head;
while(fast != null && fast.next != null){
fast = fast.next.next;
slow = slow.next;
}
return slow;
}
}
另一种解法是将其链表全部放入数组,然后返回 a[length/2];
leetcode-1290-二进制的链转整数
输入:head = [1,0,1] > 输出:5
解释:二进制数 (101) 转化为十进制数 (5)
class Solution {
public int getDecimalValue(ListNode head) {
int ans = 0 , cnt = 1;
ListNode p = reverseList(head);
while(p != null){
ans += p.val * cnt;
cnt *= 2;
p = p.next;
}
return ans;
}
public ListNode reverseList(ListNode head){
if(head == null || head.next == null) return head;
ListNode p = reverseList(head.next);
head.next.next = head;
head.next = null;
return p;
}
}
熟悉了下反转操作。最后看题解可以不反转,人啊,我的第一反应就是先反转链表,曰了;
我好蠢
class Solution {
public int getDecimalValue(ListNode head) {
int ans = 0;
while(head != null){
ans = ans * 2 + head.val;
head = head.next;
}
return ans;
}
}
leetcode-19-删除链表的倒数第 N 个节点
示例:
给定一个链表: 1->2->3->4->5, 和 n = 2.
当删除了倒数第二个节点后,链表变为 1->2->3->5.
利用前面学的递归知识,真是很开心的就用上了,fighting!!
class Solution {
int idx = 0;
public ListNode removeNthFromEnd(ListNode head, int n) {
if(n == 0)return head;
if(head == null)return null;
head.next = removeNthFromEnd(head.next,n);
idx ++;
if(idx == n)return head.next;
return head;
}
}
官方题解:双指针
利用快指针先走 n+1 步,最后快指针到末尾时,慢指针刚好到达要删的节点之前;
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode dump = new ListNode(0);//创建一个dump是防止快指针走n+1步后超过null 和 方便删除头结点,因为由题得n不会大于head的长度。
dump.next = head;
ListNode slow = dump, fast = dump;
for(int i = 0; i <= n ; i++){
fast = fast.next;
}
while(fast != null){
fast = fast.next;
slow = slow.next;
}
slow.next = slow.next.next;
return dump.next;
}
}
leetcode-24-两两交换链表中的结点
给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。
你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
给定 1->2->3->4, 你应该返回 2->1->4->3.
class Solution {
public ListNode swapPairs(ListNode head) {
ListNode dump = new ListNode(0);//利用上一题的思想。
dump.next = head;
ListNode head1 = head,prev = dump;
while(head1 != null && head1.next != null){
ListNode temp = head1.next.next;
prev.next = head1.next;
head1.next.next = head1;
head1.next = temp;
prev = head1;
head1 = temp;
}
return dump.next;
}
}
递归做法:
class Solution {
public ListNode swapPairs(ListNode head) {
if(head == null || head.next == null)return head;
ListNode next = head.next;
head.next = swapPairs(next.next);//上一个结点的下一个指向返回的这个
next.next = head;//第二个结点指向第一个结点;
return next;//返回值,为第二个结点
}
}