链表数据结构
画图辅助解题
例题1:反转链表
解法1:循环
就画图,改变每个节点的指针方向就行了。
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode reverseList(ListNode head) {
ListNode p1=null,p2=head;
while(p2!=null){
ListNode temp=p2.next;
p2.next=p1;
p1=p2;
p2=temp;
}
return p1;
}
}
解法2:递归
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode reverseList(ListNode head) {
if(head==null||head.next==null){
return head;
}
ListNode last=reverseList(head.next); //last指向反转后的头结点
head.next.next=head;
head.next=null;
return last;
}
}
例题2:从尾到头打印链表
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public int[] reversePrint(ListNode head) {
ListNode p=head;
int count=0;
while(p!=null){
p=p.next;
++count;
}
int[] result=new int[count];
p=head;
int index=count-1;
while(index>=0){
result[index--]=p.val;
p=p.next;
}
return result;
}
}
例题3:删除中间节点
如果是直接给出了要被删除的节点,并且要求在O(1)时间内完成删除操作,那遍历链表找前驱节点是不满足要求的。
(1)可以先判断是不是链表尾部的节点,如果是的话直接等于null
(2)如果不是尾部节点的话,先用要被删除节点后面那个位置的节点数据替换要被删除的节点,然后让当前节点指向后一个位置,实际上删除的是给定节点后面那个位置!
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public void deleteNode(ListNode node) {
//如果是尾节点
if(node.next==null){
node=null;
return;
}
//不是尾节点
node.val=node.next.val;
node.next=node.next.next;
return;
}
}
例题4:复杂链表的复制
解法1:hashmap
空间复杂度O(n)
/*
// Definition for a Node.
class Node {
int val;
Node next;
Node random;
public Node(int val) {
this.val = val;
this.next = null;
this.random = null;
}
}
*/
class Solution {
public Node copyRandomList(Node head) {
if(head==null){
return null;
}
Map<Node,Node> map=new HashMap<>();
Node p=head;
while(p!=null){
Node temp=new Node(p.val);
map.put(p,temp);
p=p.next;
}
p=head;
while(p!=null){
map.get(p).next=map.get(p.next);
map.get(p).random=map.get(p.random);
p=p.next;
}
return map.get(head);
}
}
解法2:拼接 + 拆分
空间复杂度O(1)
/*
// Definition for a Node.
class Node {
int val;
Node next;
Node random;
public Node(int val) {
this.val = val;
this.next = null;
this.random = null;
}
}
*/
class Solution {
public Node copyRandomList(Node head) {
if(head==null){
return null;
}
//拼接
Node p=head;
while(p!=null){
Node temp=new Node(p.val);
temp.next=p.next;
p.next=temp;
p=temp.next;
}
//赋值random
p=head;
while(p!=null){
if(p.random!=null){
p.next.random=p.random.next;
}
p=p.next.next;
}
//拆分
p=head;
Node p2=head.next,result=head.next;
while(p2.next!=null){
p.next=p.next.next;
p2.next=p2.next.next;
p=p.next;
p2=p2.next;
}
p.next=null;
return result;
}
}
例题5:两数相加
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
ListNode dummy=new ListNode(-1);
ListNode p=dummy;
int carry=0;
while(l1!=null||l2!=null){
//计算sum
int num1=l1==null?0:l1.val;
int num2=l2==null?0:l2.val;
int sum=carry+num1+num2;
//计算进位和字节值
carry=sum/10;
ListNode node=new ListNode(sum%10);
//连接节点
p.next=node;
//移动节点
p=p.next;
if(l1!=null){
l1=l1.next;
}
if(l2!=null){
l2=l2.next;
}
}
//末尾处理
if(carry==1){
p.next=new ListNode(1);
}
return dummy.next;
}
}