86. 分隔链表
1.四指针分两个子链表
2.子链表合并时注意尾指针指向空,否则会构成环
class Solution {
public ListNode partition(ListNode head, int x) {
ListNode bighead = new ListNode(0);
ListNode smallhead = new ListNode(0);
ListNode bigtail = bighead;
ListNode smalltail = smallhead;
while(head!=null){
if(head.val <x) smalltail = smalltail.next = head;
else bigtail = bigtail.next = head;
head = head.next;
}
smalltail.next = bighead.next;
bigtail.next = null;
return smallhead.next;
}
}
剑指 Offer 24. 反转链表
1.可以建立指针指向null
2.循环中每次可以建立临时指针指向当前指针的下一个,不需要建立双指针
3.可以用stack做,但是只能存val,不能存node
//方法一迭代,不能用栈直接存Node ,next指向并不为null,会产生环
class Solution {
public ListNode reverseList(ListNode head) {
ListNode cur = head,pre=null;
while(cur!=null){
ListNode temp = cur.next;
cur.next = pre;
pre = cur;
cur = temp;
}
return pre;
}
}
146. LRU 缓存机制
0.构造内部类的数据结构,key,value,前后指针
1.通过哈希表辅以双向链表实现
2.双向链表按照被使用的顺序存储了这些键值对,靠近头部的键值对是最近使用的,而靠近尾部的键值对是最久未使用的。
3.哈希表即为普通的哈希映射(HashMap),通过缓存数据的键映射到其在双向链表中的位置。
4.get时,如果cache里没有,则插入一个,否则将此节点移到头部位置
5.put时,如果cache里有,覆盖此key映射的value,并将此节点挪到头部位置,如果没有,则在头部插入并判断是否超过容量,如果超过容量,删除尾部节点
public class LRUCache {
class DLinkedNode {
int key;
int value;
DLinkedNode prev;
DLinkedNode next;
public DLinkedNode() {}
public DLinkedNode(int _key, int _value) {key = _key; value = _value;}
}
private Map<Integer, DLinkedNode> cache = new HashMap<Integer, DLinkedNode>();
private int size;
private int capacity;
private DLinkedNode head, tail;
public LRUCache(int capacity) {
this.size = 0;
this.capacity = capacity;
// 使用伪头部和伪尾部节点
head = new DLinkedNode();
tail = new DLinkedNode();
head.next = tail;
tail.prev = head;
}
public int get(int key) {
DLinkedNode node = cache.get(key);
if (node == null) {
return -1;
}
// 如果 key 存在,先通过哈希表定位,再移到头部
moveToHead(node);
return node.value;
}
public void put(int key, int value) {
DLinkedNode node = cache.get(key);
if (node == null) {
// 如果 key 不存在,创建一个新的节点
DLinkedNode newNode = new DLinkedNode(key, value);
// 添加进哈希表
// 添加至双向链表的头部
addToHead(newNode);
++size;
if (size > capacity) {
// 如果超出容量,删除双向链表的尾部节点
DLinkedNode tail = removeTail();
// 删除哈希表中对应的项
cache.remove(tail.key);
--size;
}
}
else {
// 如果 key 存在,先通过哈希表定位,再修改 value,并移到头部
node.value = value;
moveToHead(node);
}
}
private void addToHead(DLinkedNode node) {
node.prev = head;
node.next = head.next;
head.next.prev = node;
head.next = node;
}
private void removeNode(DLinkedNode node) {
node.prev.next = node.next;
node.next.prev = node.prev;
}
private void moveToHead(DLinkedNode node) {
removeNode(node);
addToHead(node);
}
private DLinkedNode removeTail() {
DLinkedNode res = tail.prev;
removeNode(res);
return res;
}
}
import java.util.*;
/*
* public class ListNode {
* int val;
* ListNode next = null;
* }
*/
public class Solution {
/**
*
* @param l1 ListNode类
* @param l2 ListNode类
* @return ListNode类
*/
public ListNode mergeTwoLists (ListNode l1, ListNode l2) {
// write code here
ListNode p=new ListNode(0);
ListNode q=p ;
while(l1 != null && l2!= null){
if(l1.val <l2.val){
p.next = l1;
l1 = l1.next;
}else{
p.next=l2;
l2= l2.next;
}
p = p.next;
}
if(l1!=null) p.next=l1;
if(l2 != null) p.next=l2;
return q.next;
}
}
每k个一组翻转链表
1.双栈,但是两层while 会超时,最外层while(head!=null)超时,设置为while(true)不会
public ListNode reverseKGroup (ListNode head, int k) {
// write code here
Stack<ListNode> stack1 =new Stack();
Stack<ListNode> stack2 =new Stack();
ListNode p = new ListNode(0);
ListNode q = p;
while(true){
int num = 0;
ListNode t = head;
while(num<k&&t!=null){
stack1.push(t);
t = t.next;
num++;
}
if(num!=k){
p.next = head;
break;
}else{
while(!stack1.isEmpty()){
p=p.next = stack1.pop();
}
head = t;
}
}
return q.next;
}
链表中环的入口结点
1.集合解题
public class Solution {
public ListNode detectCycle(ListNode head) {
Set<ListNode> set = new HashSet<ListNode>();
ListNode p = head;
while(p!=null){
if(set.contains(p)) return p;
else {
set.add(p);
p = p.next;
}
}
return null;
}
}
2.快慢指针
public class Solution {
public ListNode detectCycle(ListNode head) {
ListNode fast = head;
ListNode slow = head;
while( fast !=null && fast.next!=null){
fast = fast.next.next;
slow= slow.next;
if(fast == slow){
ListNode fast2 = head;
while(fast2!=slow){
fast2 = fast2.next;
slow = slow.next;
}
return fast2;
}
}
return null;
}
删除链表的倒数第 nn 个节点
1.利用快慢指针,慢指针比快指针慢N步,那么当快指针到末尾,则慢指针指向倒数第n个节点,
关键在于判读慢指针是否指向头节点,因为删除节点需要知道此节点的前一节点,而头节点没有前一节点
public ListNode removeNthFromEnd (ListNode head, int n) {
// write code here
ListNode p = head;
ListNode q = head;
ListNode pre = head;
int i=0;
while(p!=null&&i<n){
++i;
p = p.next;
}
while(p!=null){
pre = q;
q = q.next;
p = p.next;
}
ListNode target;
if(q!=head){
pre.next = q.next;
}else{
head = head.next;
}
return head;
}
合并k个已排序的链表
牛客题目链接
合并\ k k 个已排序的链表并将其作为一个已排序的链表返回。分析并描述其复杂度。
思路:用优先队列建一个小顶堆,每次堆顶为值最小的节点,依次取出,然后再将它的下一个节点放回去。
再重复过程~
public ListNode mergeKLists(ArrayList<ListNode> lists) {
Queue<ListNode> pq = new PriorityQueue<>((v1,v2)->v1.val-v2.val);
for(ListNode node:lists){
if(node !=null) pq.offer(node);
}
ListNode head = new ListNode(0);
ListNode tail = head;
while(!pq.isEmpty()){
ListNode temp = pq.poll();
tail.next = temp;
tail = temp;
if(temp.next !=null) pq.offer(temp.next);
}
return head.next;
}
删除链表第K个结点
//删除链表第k个节点
//1、先找到第k个节点的位置(从头节点开始走k-1步)
//2、删除,先链接再删除
#define _CRT_SECURE_NO_WRANINGS
#include<iostream>
#include<stdlib.h>
#include<cstdio>
using namespace std;
struct list_node{
int val;
struct list_node * next;
}; //链表的节点
int K;
list_node * input_list(void) //读入链表
{
int n, val;
list_node * phead = new list_node();
list_node * cur_pnode = phead;
scanf_s("%d %d", &n, &K);
for (int i = 1; i <= n; ++i) {
scanf_s("%d", &val);
if (i == 1) {
cur_pnode->val = val;
cur_pnode->next = NULL;
}
else {
list_node * new_pnode = new list_node();
new_pnode->val = val;
new_pnode->next = NULL;
cur_pnode->next = new_pnode;
cur_pnode = new_pnode;
}
}
return phead;
}
list_node * remove_kth_node(list_node * head, int K)
{
//在下面完成代码
if (head == NULL)
//链表为空,直接返回
return NULL;
list_node* fast = head;
if (K == 1)
//删除第一个节点,头删
{
head = head->next;
return head;
}
while (--K){
if (fast == NULL || fast->next == NULL)
return NULL;
fast = fast->next;
}
if (fast->next)//找到第k个节点,构思尾删
{
fast->val = fast->next->val;
//把第k个节点和第k-1个节点的值交换
list_node*del = fast->next;
//标记fast->next;
fast->next = fast->next->next;
//链接
free(del);
}
else{
//尾删
free(fast);
}
return head;
}
void print_list(list_node * head)
{
while (head != NULL) {
printf_s("%d ", head->val);
head = head->next;
}
}
int main()
{
list_node * head = input_list(); // 链表的头节点
list_node * rhead = remove_kth_node(head, K);
print_list(rhead);
system("pause");
return 0;
}