LeetCode25 Un conjunto de K nodos invertidos lista enlazada

LeetCode25 Un conjunto de K nodos invertidos lista enlazada

Ayer, me encontré con esta pregunta de la entrevista durante mi entrevista de pasantía en el grupo empresarial de recomendación y búsqueda de cuentas de suscripción de Tencent.

tema

Se le proporciona el nodo principal de la lista vinculada heady cada knodo se invierte en un grupo. Devuelva la lista vinculada modificada. kes un número entero positivo cuyo valor es menor o igual a la longitud de la lista vinculada. Si el knúmero total de nodos no es un múltiplo entero de , igualmente se invertirá normalmente.

No puede simplemente cambiar el valor dentro del nodo, realmente necesita intercambiar el nodo.

ejemplo,

1->3->2->4->5->6->7->8,k = 3

Resultado: 2->3->1->6->5->4->8->7

El código original que di es el siguiente:

Node* reverse(Node* first, int k){
  if(first==NULL){
    return NULL;
  }
  int t = 0;
  Node* pre = first;
  Node* cur = first;
  // 1-> 2-> 4-> 5-> 6  k = 2;
  Node* cur_tail = first;
  Node* last_tail = first;
  while(cur!=NULL){
    Node* tem = new Node(-1);
    tem = cur;
    tem->next = pre;
    cur = cur->next;
    pre = tem;
    t++;
    t = t%k;
    if(t % k == 0){
      cur_tail = cur;
      last_tail->next = cur_tail;
      last_tail = cur_tail;
    }
  }
}

El método de agrupación que adopto es utilizar números para juicios especiales y no registrar el nodo principal de la lista vinculada después del cambio.

Después de la investigación, esta pregunta es una variante de LeetCode25.

Likou 25: Te daré el nodo principal de la lista vinculada heady kvoltearé cada nodo en un grupo. Por favor, devuelve la lista vinculada modificada. kes un número entero positivo cuyo valor es menor o igual a la longitud de la lista vinculada. Si el knúmero total de nodos no es un múltiplo entero de , los últimos nodos restantes se mantienen en su orden original.

Esta es una oportunidad para escribir un artículo sobre la expresión verbal, porque descubrí que usar oraciones afirmativas cuando se usan frases verbo-objeto es más contagioso que usar oraciones negativas. Por ejemplo, la última oración aquí también se puede expresar como: Si el número total de nodos no es un múltiplo entero de k, el último nodo restante no se invertirá. Para expresarlo, no existe expresión más vívida e intuitiva que "mantener los últimos nodos restantes en su orden original".

De vuelta a los negocios.

Ideas

Agrupe las listas enlazadas en grupos de k y voltéelas individualmente. Por lo tanto, puede utilizar una cola de puntero para señalar el nodo de cola de cada grupo por turno. Este puntero avanza k pasos cada vez hasta el final de la lista vinculada y utiliza un encabezado de puntero para registrar el nodo principal de cada grupo. El nodo principal del siguiente grupo es el nodo posterior del nodo de cola del grupo actual. Para cada grupo, primero determinamos si su longitud es mayor o igual a k. Si es así, voltee esta parte de la lista vinculada; de lo contrario, no es necesario voltear.

La siguiente pregunta es cómo invertir la sublista dentro de un grupo. Al mismo tiempo, también es necesario conectar el encabezado de la lista subenlazada con la lista subenlazada anterior y la cola de la lista subenlazada con la siguiente lista subenlazada. Por lo tanto, necesitamos registrar el nodo principal de la lista subvinculada, el nodo anterior del encabezado, la cola del nodo final de la lista vinculada actual y usar una variable temporal nex para registrar el nodo principal del siguiente enlace. lista.

Para la primera sublista, no hay ningún nodo antes de su nodo principal. Si no hay ningún nodo, cree un cabello de nodo y apunte antes al nodo.

Si la longitud total de la lista vinculada es menor que k, entonces se devuelve hair->next. Si la longitud total de la lista vinculada es mayor que k, durante el ciclo, pre->next se modificará para que apunte a la cabeza. nodo de la siguiente lista subenlazada. En la primera lista subenlazada, pre apunta al cabello, por lo que cabello->siguiente también apunta al nodo principal después de invertir la primera lista subenlazada. Por lo tanto, no importa si se invierte la primera lista subenlazada o si se mantiene el orden original, hair->next devuelve el nodo principal de la lista enlazada final.

// 翻转一个子链表,并且返回新的头与尾
pair<ListNode*, ListNode*> myReverse(ListNode* head, ListNode* tail){
 	ListNode* prev = tail->next;
  ListNode* p = head;
  while(prev!=tail){
    ListNode* nex = p->next;
    p->next = pre;
    prev = p;
    p = nex;
  }
  return {prev,head};
}

ListNode* reverseKGroup(ListNode* head, int k){
  ListNode* hair = new ListNode(0);
  hair->next = head;
  ListNode* pre = hair;
  while(head){
    ListNode* tail = prev;
    //查看剩余部分长度是否大于等于k
    for(int i = 0;i<k;++i){
      tail = tail->next;
      if(!tail){
        return hair->next;
      }
    }
    //现在的tail是第一个k个节点的子链表的尾节点
    ListNode* nex = tail->next; //下一组的头节点
    // head是当前一组的头节点
    pair<ListNode*, ListNode*> result = myReverse(head, tail);
    head = result.first; // head是当前组的尾节点,反转之后成了头节点
    tail = result.second; // tail是当前组的头节点,翻转之后成了尾节点
    //把子链表重新接回原链表
    pre->next = head;
    tail->next = nex;
    pre = tail;  // pre指向了当前组翻转之后的尾节点。
    head = nex; // head指向下一组的头节点
  }
  return hair->next;
}

Comprender las subrutinas para invertir listas vinculadas

Es como si los estudiantes de primaria estuvieran haciendo fila ahora. Todos se paran a la derecha y ponen sus manos sobre los hombros de las personas de la derecha. La última persona no tiene un lugar donde descansar y se apoya en un gran árbol. Este gran árbol es llamado NULO.

1. Ahora solo la persona del extremo izquierdo está despierta, el resto está borracho y solo la persona de la izquierda puede despertar a la de la derecha.

2. Y la persona de la izquierda olvidará a la persona de la derecha después de darse la vuelta.

3. La primera persona de la izquierda siempre recuerda claramente la posición de la última persona.

4. Hay una persona en el sitio que puede recordar muchos lugares.

¿Cómo puedo hacer que toda la gente de la derecha le dé la mano a la gente de la izquierda?

A->B->C->D->E->Árbol grande

Respuesta: Primero, las personas en el lugar recuerdan la posición de la persona B a la derecha del pequeño A y la posición del pequeño A, y luego la mano del pequeño A se coloca en el gran árbol.

Pida a las personas presentes que recuerden la posición de C, la persona a la derecha de B y su propia posición. B pone su mano sobre el hombro de A.

Recuerde la posición de D, la persona a la derecha de C y su propia posición. C pone su mano sobre el hombro de B.

Recuerde la posición de E, la persona a la derecha de D y su propia posición. D pone su mano sobre el hombro de C.

Recuerde la posición del gran árbol y su propia posición en el lado derecho de E. E pone su mano sobre el hombro de D.

En este punto, E puso su mano sobre D y se dio la vuelta. (Por lo tanto, la condición para completar el turno es que la posición del subconjunto de memoria anterior de la persona presente sea la posición de la persona más a la derecha)

Experiencia: cuando utiliza ejemplos de la vida para comprender los algoritmos, los algoritmos se vuelven más vívidos e interesantes.

Reflexión y resumen

En el proceso de diseño del programa, puede enumerar de antemano qué punteros globales son, qué punteros globales apuntan a cambios y qué puntos son fijos. Y señale el propósito de cada indicador, lo cual es útil para aclarar ideas.

Puntero global:

  • puntero dinámico

head apunta al nodo principal de la lista subenlazada actual.

tail apunta al nodo de cola de la lista subenlazada actual

pre apunta al nodo anterior de la sublista actual

  • puntero inmutable

El cabello del nudo de la cabeza antes de la cabeza.

Puntero local:

puntero siguiente: almacena el nodo principal de la siguiente lista subenlazada

Variación: si el grupo tiene menos de k nodos, aún así invertir

Solo necesita cambiar el código que determina si el número de nodos en el grupo actual es mayor o igual que k para encontrar el nodo de cola del grupo actual.

ListNode* reverseKGroup(ListNode* head, int k){
  ListNode* hair = new ListNode(0);
  hair->next = head;
  ListNode* pre = hair;
  while(head){
    ListNode* tail = prev;
    //找出该组的尾节点
    for(int i = 0;i<k && tail->next!=NULL;++i){
      tail = tail->next;
    }
    //现在的tail是第一个k个节点的子链表的尾节点
    ListNode* nex = tail->next; //下一组的头节点
    // head是当前一组的头节点
    pair<ListNode*, ListNode*> result = myReverse(head, tail);
    head = result.first; // head是当前组的尾节点,反转之后成了头节点
    tail = result.second; // tail是当前组的头节点,翻转之后成了尾节点
    //把子链表重新接回原链表
    pre->next = head;
    tail->next = nex;
    pre = tail;  // pre指向了当前组翻转之后的尾节点。
    head = nex; // head指向下一组的头节点
  }
  return hair->next;
}

Supongo que te gusta

Origin blog.csdn.net/ChenglinBen/article/details/132246070
Recomendado
Clasificación