0 preguntas
Ingrese una lista vinculada y genere el k-ésimo nodo de la parte inferior de la lista vinculada .
1 Análisis de ideas
Método: método de ventana deslizante
Establezca el tamaño de la ventana deslizante en K
La naturaleza de la ventana deslizante: el número de puntos restantes es K-1. Los datos del punto de retorno después de la ventana deslizante son N- (K-1).
La solución general: primero recorra la lista enlazada individualmente para obtener el número total de nodos n de la lista enlazada, luego el nodo n-k + 1 es el k-ésimo nodo desde la parte inferior. Entonces, atraviesa el nodo n-k + 1 por segunda vez.
Podemos resolver este problema con la idea de la ventana deslizante: el tamaño de la ventana es K, y seguir moviendo la ventana hasta que el borde derecho de la ventana sea NULL y ya no se mueva. En este momento, el borde izquierdo del ventana es el punto que está buscando. Los iconos son los siguientes:
Soluciones:
(1) Establezca la posición inicial de los dos punteros para encabezar
(2) Deje que el primer puntero mueva primero los pasos K-1. En este momento, la diferencia de longitud de paso entre el puntero 1 y el puntero 2 es k, lo que equivale a determinar el tamaño de la ventana deslizante.
(3) Entonces toda la ventana se desliza. La condición final del deslizamiento es cuando el puntero de p está vacío, en este momento la posición del puntero de p2 es el nodo que estamos buscando.
2 Ejemplo de código
package com.dandan.builder.suanfa;
public class Solution1 {
public ListNode FindKthToTail(ListNode head,int k){
/*
*
k 如果 比我们的链表的长度还要大的话,我们直接返回None
k 如果小于链表的长度,我们可以定义两个变量,这两个变量中间间隔k
用两个指针做一个尺子,然后让尺子在跳跳,然后就会找到 第k 个结点
*
*/
// 鲁棒性:输入参数的检查
if(head == null || k <= 0){
return null;
}
//定义连个指针,第一个指针和第二个指针。两个指针都是从头开始
ListNode firstPoint = head;
ListNode secondPoint = head;
//首先让一个指针先开始移动,移动k-1步时,找到了一次滑动的子窗口。
for (int i = 0; i <k-1 ; i++) {
//如果当第一个指针走到null的话,说明K的长度已经超过链表的长度需要返回null。
//判断的时候在每一次指针往前走的时候判断。因为在最后一个节点时,节点指向null
if(firstPoint == null){
return null;
}
//第一个指针一直往前走
firstPoint=firstPoint.next;
}
//循环结束后firstPoint已经走到K的位置
//此时移动两个指针(移动步长)
//当第一个指针(先走的指针,窗口(步长)的尾端)指向为null的时候,说明不能在移动了
while(firstPoint.next != null){
firstPoint=firstPoint.next;
secondPoint = secondPoint.next;
}
//循环结束后secondPoint位置就是需要的倒数K个点
return secondPoint;
}
public static void main(String[] args) {
int[] nums = {1, 2, 3, 4, 6, 5, 6};
ListNode head = new ListNode(nums);
System.out.println(head);
ListNode res = (new Solution1()).FindKthToTail(head,3);
System.out.println(res);
}
}
public class ListNode {
int val;
ListNode next;
public ListNode(int val) {
this.val = val;
}
//链表节点的构造函数
//使用arr为参数,创建一个链表,当前的ListNode为链表的头节点
public ListNode(int[] arr){
if(arr.length == 0 || arr == null){
throw new IllegalArgumentException("arr can not be empty");
}
this.val = arr[0];
ListNode cur = this;
for (int i = 1; i <arr.length ; i++) {
cur.next = new ListNode(arr[i]);
cur=cur.next;
}
}
@Override
public String toString(){
StringBuilder res = new StringBuilder();
ListNode cur = this;
while(cur != null){
res.append(cur.val + "->");
cur=cur.next;
}
res.append("NULL");
return res.toString();
}
}
Los resultados de la prueba son los siguientes:
3 Optimización de código (pensamiento de ventana deslizante)
- 1. Primero defina dos punteros antes y el último apuntando al encabezado de la lista enlazada;
- 2. El puntero anterior del chelín apunta al k-ésimo nodo;
- 3. Luego, los dos punteros se mueven hacia atrás al mismo tiempo, y finalmente pre apunta al nodo de cola, y el último apunta al k-ésimo nodo desde la parte inferior;
- 4. Cuando k es cero o el nodo está vacío, devuelve un valor nulo.
Iterar solo una vez
public ListNode FindKthToTail2(ListNode head, int k){
// 定义两个指针
ListNode pre = head;
ListNode last = head;
int i = 0;
for (; pre.next != null; i++) {
if(i >= k-1){
// 此时pre指针走了k-1步,后面两个指针一起向后遍历
last = last.next;
}
pre = pre.next;
}
// 考虑鲁棒性
return i < k ? null : last;
}
El código sigue optimizándose
public ListNode FindKthToTail3(ListNode head, int k){
// 定义两个指针
ListNode pre ;
ListNode last;
for (pre=last=head; pre.next != null; pre = pre.next,k--) {
if(k<=1){
// 此时pre指针走了k-1步,后面两个指针一起向后遍历
last = last.next;
}
}
// 考虑鲁棒性
return k<=1 ? last : null;
}