链表专题
链表
个人心得是链表专题得画图,画图能让你更快理清思路!!!!
加上链表专题,大多数使用的都是双指针,快慢指针等方法,有时候甚至会使用到三指针
画图能够让你直到每个指针的指向,不至于思路混乱
lc203.移除链表元素
以后链表题尽量使用虚拟头节点,能让处理所有节点都是一样的
class Solution {
public ListNode removeElements(ListNode head, int val) {
//利用虚拟头节点,就不需要特值判断,保证代码的优雅
ListNode node= new ListNode(val-1);
node.next=head;
ListNode p=node;
while(p.next!=null){
if(p.next.val==val){
p.next=p.next.next;
}else{
p=p.next;
}
}
return node.next;
}
lc206.反转链表
双指针
class Solution {
public ListNode reverseList(ListNode head) {
//双指针
ListNode p=null;
ListNode q=head;
while(q!=null){
q=head.next;
head.next=p;
p=head;
head=q;
}
return p;
}
}
19.删除链表的倒数第n个节点
方法一:
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
if(head==null||head.next==null) return null;
ListNode fast=head;
ListNode slow=head;
while(n!=0){
fast=fast.next;
n--;
}
//如果fast走出n步,已经为null了
if(fast==null) return head.next;
while(fast.next!=null){
fast=fast.next;
slow=slow.next;
}
slow.next=slow.next.next;
return head;
}
}
方法二:更推荐,代码更为优雅
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
//推荐大家使用虚拟头结点,这样方便处理删除实际头结点的逻辑
ListNode node=new ListNode(0,head);
ListNode fast=head;
ListNode slow=node;
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 node.next;
}
}
lc24.两两交换链表中的节点
一刷:想法是根据题意模拟,使用双指针
链表类题目一定要画图
class Solution {
public ListNode swapPairs(ListNode head) {
//双指针不够,要三指针,太麻烦了
ListNode node=new ListNode(0,head);//虚拟头节点
ListNode cur=node;
while(cur.next!=null&&cur.next.next!=null){
ListNode tmp=cur.next;
ListNode tmp1=cur.next.next.next;
cur.next=tmp.next;
cur.next.next=tmp;
cur.next.next.next=tmp1;
cur=cur.next.next;//向后移动俩位,准备下一轮交换
}
return node.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;
}
}
面试题 02.07. 链表相交
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
ListNode pa=headA;
ListNode pb=headB;
while(pa!=pb){
pa=pa==null?headB:pa.next;
pb=pb==null?headA:pb.next;
}
return pa;
}
}
lc141.环形链表
public class Solution {
public boolean hasCycle(ListNode head) {
if(head==null||head.next==null) return false;
ListNode fast=head.next;
ListNode slow=head;
while(fast!=slow){
if(fast==null||fast.next==null) return false;
fast=fast.next.next;
slow=slow.next;
}
return true;
}
}
lc142.环状链表Ⅱ
方法一.哈希表
public class Solution {
public ListNode detectCycle(ListNode head) {
ListNode p=head;//工作指针
Set<ListNode> visited=new HashSet<ListNode>();
while(p!=null){
if(visited.contains(p)){
return p;
}else{
visited.add(p);
}
p=p.next;
}
return null;
}
}
方法二.快慢指针
带点数学推导
public class Solution {
public ListNode detectCycle(ListNode head) {
ListNode fast=head,slow=head;
while(true){
if(fast==null||fast.next==null) return null;
fast=fast.next.next;
slow=slow.next;
if(fast==slow) break;
}
fast=head;
while(slow!=fast){
fast=fast.next;
slow=slow.next;
}
return fast;
}
}
lc707.设计链表(二刷!!!!)
单链表法
class ListNode{
int val;
ListNode next;
ListNode(int val){
this.val=val;
}
}
class MyLinkedList {
int size;
ListNode head;//虚拟头节点
//初始化链表
public MyLinkedList() {
size=0;
head=new ListNode(0);
}
//获取第index个节点的数值
public int get(int index) {
if(index<0||index>=size){
return -1;
}
ListNode p=head;
for(int i=0;i<=index;++i){
p=p.next;
}
return p.val;
}
//在链表最前面插入一个节点
public void addAtHead(int val) {
addAtIndex(0,val);
}
//将一个值为 val 的节点追加到链表中作为链表的最后一个元素
public void addAtTail(int val) {
addAtIndex(size,val);
}
//将一个值为 val 的节点插入到链表中下标为 index 的节点之前
public void addAtIndex(int index, int val) {
if(index>size) return;
if(index<0) index=0;
size++;
//找到要插入节点的前驱
ListNode pred=head;
for(int i=0;i<index;++i){
pred=pred.next;
}
ListNode toAdd=new ListNode(val);
toAdd.next=pred.next;
pred.next=toAdd;
}
//如果下标有效,则删除链表中下标为 index 的节点
public void deleteAtIndex(int index) {
if(index<0||index>=size){
return;
}
size--;
ListNode pred=head;
for(int i=0;i<index;++i){
pred=pred.next;
}
pred.next=pred.next.next;
}
}
/**
* Your MyLinkedList object will be instantiated and called as such:
* MyLinkedList obj = new MyLinkedList();
* int param_1 = obj.get(index);
* obj.addAtHead(val);
* obj.addAtTail(val);
* obj.addAtIndex(index,val);
* obj.deleteAtIndex(index);
*/