链表(Linked list)是一种常见的基础数据结构,是一种线性表,但是并不会按线性的顺序存储数据,而是在每一个节点里存到下一个节点的指针(Pointer)。
使用链表结构可以克服数组需要预先知道数据大小的缺点,链表结构可以充分利用计算机内存空间,实现灵活的内存动态管理。但是链表失去了数组随机读取的优点,同时链表由于增加了结点的指针域,空间开销比较大。
删除链表中重复元素(排序链表)
思路:有序链表,遍历当前节点和下一个节点相等,删除即可
public ListNode deleteDuplicates(ListNode head) {
ListNode list = head;
while(list!=null){
if(list.next==null){
break;
}
if(list.val == list.next.val){
list.next = list.next.next;
}else{
list = list.next;
}
}
return head;
}
删除链表的倒数第N个节点
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode start = new ListNode(0);
ListNode slow = start, fast = start;
slow.next=head;
fast.next=head;
//fast指针每次多走一步,n+1次多走n+1步
for (int i = 1; i <= n + 1; i++) {
fast = fast.next;
}
//找到第n+1个节点
while (fast != null) {
slow = slow.next;
fast = fast.next;
}
//删除节点
slow.next = slow.next.next;
return start.next;
}
}
环形链表(给定一个链表,判断链表中是否有环)
思路:快慢指针,一定会相遇
public static boolean hasCycle(ListNode head) {
if(head==null){
return false;
}
ListNode fast=head;
ListNode slow=head;
while(fast!=null && fast.next!=null){
fast=fast.next.next;
slow=slow.next;
if(slow==fast){
return true;
}
}
return false;
}
相交链表:找到两个单链表相交的起始节点
思路:1.消除长度,2.找相同节点
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
int lenA = length(headA), lenB = length(headB);
while(lenA > lenB){
headA=headA.next;
lenA--;
}
while(lenA < lenB){
headB=headB.next;
lenB--;
}
while(headA!=headB){
headA=headA.next;
headB=headB.next;
}
return headA;
}
private int length(ListNode node) {
int length = 0;
while (node != null) {
node = node.next;
length++;
}
return length;
}
反转链表
思路:前置节点为NULL,遍历原链表,当前节点的next指向pre,重置pre节点和curr节点
public ListNode reverseList(ListNode head) {
ListNode curr = head,pre=null;
while(curr!=null){
ListNode next=curr.next;
curr.next=pre;
pre=curr;
curr=next;
}
return pre;
}
回文链表
思路:使用快速和慢速指针查找列表的中间位置。这意味着当快速指针到达最后一个末尾时,慢速指针将到达中间,然后反转最后一半,并将列表前半部分中的每个元素与后半部分中的元素进行比较。
public boolean isPalindrome(ListNode head) {
ListNode fast = head;
ListNode slow = head;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
}
if (fast != null) {
slow = slow.next;
}
//后半部分
slow = reverse(slow);
while (slow != null && head.val == slow.val) {
head = head.next;
slow = slow.next;
}
return slow == null;
}
链表的中间节点
思路:双指针
public ListNode middleNode(ListNode head) {
ListNode fast = head;
ListNode slow = head;
while(fast != null && fast.next != null){
fast = fast.next.next;
slow = slow.next;
}
return slow;
}