# [LeetCode skimming - data structure]

Posted by cmason22 on Thu, 13 Jan 2022 17:00:00 +0100

## 2022 winter vacation LeetCode question brushing - task 01: linked list

Introduction: the author is basically Xiaobai, so this topic brushing meeting is a difficult process. At the same time, it is also through this team learning to pick up the previous knowledge, and more importantly, it is to expand and consolidate. Therefore, this blog may be long and have a review of basic knowledge, which is also a record I completed step by step in the process of doing the question. (some didn't work out the answer)

1, Array Basics
(Title: 0189) rotate array
Title: give you an array, rotate the elements in the array to the right K positions, where k is a non negative number.

The first thing to be clear about:
The difference between vector and array
The standard template library (STL) of C + + is a collection of 13 containers, and vector is one of them. Dynamic array vector is an array whose capacity changes dynamically. When defining a vector object, you don't need to specify the size of the array first. If there is data, you can insert it into the array. Vector manages its own storage space.

Header file and namespace of vector:

```#Include < vector > / / Note: No h
using namespace std; //In std standard namespace
```

Definition of vector
vector can adapt to any type. It is a class template.

```vector<int> arr_int; //Defines the dynamic array of int when an internal element is defined;
vector<char> arr_char; //A dynamic array whose internal element is char is defined;
vector<CStudent> arr_student; //Defines a dynamic array whose internal element is CStudent;
vector<char*> arr_pchar; //Defines a dynamic array whose internal element is char *
```

Supplement: differences between public, private and protected

• public means common: the data members and functions of a class can be accessed by the class objects and derived classes
• Private private type: its own class can be accessed, but derived classes cannot.
• protected: self classes and derived classes can access private members equivalent to themselves. The difference between it and private is the difference between derived classes.

Linked List: a linear list data structure. It uses a set of arbitrary storage units (which can be continuous or discontinuous) to store a set of data with the same type.

First element node: refers to the node where the first data element is stored in the linked list
Head node: a node attached before the first node of the linked list
The difference between linked list and array: array is continuous in logic and physical storage; The linked list is logically continuous, but not necessarily continuous in physical storage. Therefore, a node of the linked list has a data field and a pointer field to store the address of the next node.
Traversal mode: array is random access and linked list is sequential access.

First, supplement the basic operations of the single linked list:

1. Definition and representation
2. Destroy
3. Find the length of single linked list
4. Value
5. Find (find by value)
6. Insert: insert a new node before the ith node
7. Delete: deletes the i th node

Algorithm - definition and representation of single linked list:

```typedef struct Lnode{  //Declare the type of the node and the pointer type to the node
ElemType data;          //Data field of node
struct Lnode *next;     //Pointer field of node

/* (1)Generate a new node as the head node, and point to the head node with the head pointer L
(2)Set the pointer field of the header node to null
*/
L = new LNode;  //Or L=(LinkList) malloc(sizeof(LNode));
L->next=NULL;
return OK;
}
```

Algorithm - destruction of single linked list: the linked list does not exist after destruction
Starting from the pointer, release all nodes in turn

```Status DestroyList_L(LinkList &L){  //Destroy single linked list L
while(L){
p = L;
L = L->next;
delete p;
}
return OK;
}
```

Algorithm - single linked list emptying:
The linked list still exists, but there are no elements in the linked list. It becomes an empty linked list (the head pointer and head node still exist). (release all nodes in turn and set the pointer field of the header node to null)

```Status ClearList(LinkList &L){    //Reset L to empty table
p=L->next;
while(p){          //It's not at the end of the watch
q=p->next;
delete p;
p=q;
}
L->next=NULL;      //The header node pointer field is null
return OK;
}
```

Algorithm - find the table length of single linked list:

```int ListLenght_L(LinkList L){  //Returns the number of data elements in L
p=L->next;       //p points to the first node
i=0;
while(p){        //Traverse the single linked list and count the summary points
i++;
p=p->next;
}
return i;
}
```

Algorithm - value of single linked list:
Starting from the head pointer of the linked list, search down the chain domain next node by node until the ith node is searched.

```Status GetElem_L(LinkList,int i,ElemType &e){ //Get the content of a data element in the linear table and return it through the variable e
p=L->next;j=1;         //initialization
while(p&&j<i){         //Scan backward until p points to the ith element or p is empty
p=p->next;++j;
}
if(!p||j>i) return ERROR;  //The ith element does not exist
e=p->data;                 //Take the i th element
return OK;
}//GetElem_L
```

Algorithm - single linked list lookup:

```//Find by value - get the location (address) of the data according to the specified data
//Find the data element with the value e in the linear table L
//If it is found, the data element with the value e in L is returned. If the search fails, NULL is returned
p=L->next;
while(p&&p->data!=e)
p=p->next;
return p;
}
//Find by value - obtain the serial number of the data location according to the specified data
//Returns the position sequence number of the data element with e in L. if the search fails, it returns 0
p=L->next;j=1;
while(p&&p->data!=e)
{p=p->next; j++;}
if(p)  return j;
else return 0;
}
```

Algorithm - single linked list insertion: insert a new node with the value of e before the ith node

```//Insert the data element e before the ith element in L
p=L;j=0;
while(p&&j<i-1) {p=p->next; ++j;}
if(!p||j>i-1) return ERROR;
s=new LNode; s->data=e; //Generate a new node s and set the data field of node s to e
s->next=p->next;        //Insert node s into L
p->next=s;
return OK;
}
```

Algorithm -- deletion of single linked list: delete the ith node

```//Delete the ith data element in linear table L
p=L;j=0;
while(p->next&&j<i-1) {p=p->next; ++j;} //Find the ith node and point p to its precursor
if(!(p->next)||j>i-1) return ERROR;
q=p->next;          //Temporarily save the address of the deleted node for release
p->next=q->next;    //Change the pointer field of the precursor node of the deleted node
e=q->data;          //Save delete node data field
delete q;           //Free up space for deleting nodes
return OK;
}
```

(Title No.: 0707) the title is omitted.

0707 problem solution: here refer to a code written by a teammate:

```#include<iostream>

using namespace std;

public:
//An empty table that contains only header nodes
}

int get(int index) {
LNode* p = head->next; //Initialization, p points to the first element node
int k = 0; //For counting
while (p && k < index) {  //p points to the ith element node or p is empty to exit the loop
p = p->next;
k++;
} //The condition for loop exit is k=i or reaching the end of the single linked list

if (!p || k > index) return -1; //The index element does not exist
int e = p->val;
return e;
}

}

LNode* p = head; //Positioning with p
LNode* temp = new LNode(val, NULL); //To insert
while (p->next) { //p points to the last node
p = p->next;
}
p->next = temp;
}

void addAtIndex(int index, int val) {

int k = -1; // k is the counter
while (p && k < index - 1) { //Until p points to the i-1 or p is empty
p = p->next;
k++;
}
if (!p || k > index - 1) return; //Cannot insert
LNode* s = new LNode(val, p->next); //New node
p->next = s;
}

void deleteAtIndex(int index) {
int k = -1; //k is the counter
while (p->next && k < index - 1) { //Find the precursor of the deleted node
p = p->next;
k++;
}
if (!(p->next) || k > index - 1) return;
LNode* q = p->next; //Make q point to the node to be deleted
p->next = q->next;
}
void print() {
while (p) {
cout << p->val << " ";
p = p->next;
}
cout << endl;
}
private:
struct LNode {
int val;
struct LNode* next;
LNode(int x,LNode* node) {
val = x;
next = node;
}
};
};

//Test process
int main() {
l->print();
l->print();
l->print();
l->print();
l->get(1);
l->print();
l->deleteAtIndex(1);
l->print();
}
```

Solution idea: turn the linked list in place. Set two pointers, curr and preNode, to reverse the single linked list. Except for the head node, the directions of other nodes are reversed. Use curr to point to the current node and save the address of the next node pointed by the node. Next, the node points to the previous node again. Here, use preNode to point to the previous node of the node, That is, the subsequent node of the node pointed to by curr is the node pointed to by preNode. Assign curr to preNode and next to curr, that is, move backward in sequence and repeat the above reverse operation until curr points to NULL, and the preNode points to the last node of the original linked list, and preNode is also the first node of the result linked list.

0206 problem solution:

```class Solution {
public:
ListNode* preNode = NULL;
while(curr != NULL){
ListNode* next = curr->next;
curr->next = preNode;
preNode = curr;
curr = next;
}
return preNode;
}
};
```

The following algorithm is bubble sorting. The test results are correct, but the force buckle submission results timeout. The reason is that the input linked list tested at the time of submission is too long, and the time complexity of bubble sorting is O(n^2), which can not meet the requirements.

```/**
* struct ListNode {
*     int val;
*     ListNode *next;
*     ListNode() : val(0), next(nullptr) {}
*     ListNode(int x) : val(x), next(nullptr) {}
*     ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* tail = NULL;
int value = 0;

while(node_i){
while(node_j && node_j->next != tail){
if(node_j->val > node_j->next->val)
{value = node_j->next->val; node_j->next->val = node_j->val; node_j->val = value;}
node_j = node_j->next;
}
tail = node_j;
node_i = node_i->next;
}
}
};
```

Reselect a sorting method:
The time complexity of linked list selection and sorting is O(n^2);
The time complexity of linked list insertion sorting is O(n^2);
The time complexity of linked list merging and sorting is O(nlogn);
The time complexity of linked list counting and sorting is O(n^2);
The time complexity of linked list selection and sorting is O(n^2);

Here, only the linked list merging and sorting method is selected for the test:

```//Linked list merge sort
/**
* struct ListNode {
*     int val;
*     ListNode *next;
*     ListNode() : val(0), next(nullptr) {}
*     ListNode(int x) : val(x), next(nullptr) {}
*     ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
while(fast && fast->next){
fast = fast->next->next;
slow = slow->next;
}
ListNode* mid = slow->next;
slow->next = nullptr;
}
private:
ListNode* merge(ListNode* l1, ListNode* l2){
ListNode dummy(0);
ListNode* tail = &dummy;
while(l1 && l2){
if(l1->val > l2->val) swap(l1, l2);
tail->next = l1;
l1 = l1->next;
tail = tail->next;
}
if(l1) tail->next = l1;
if(l2) tail->next = l2;
return dummy.next;
}
};
```

The above merging algorithm is submitted for approval.

(0147) Title: insert and sort the linked list

```/**
* struct ListNode {
*     int val;
*     ListNode *next;
*     ListNode() : val(0), next(nullptr) {}
*     ListNode(int x) : val(x), next(nullptr) {}
*     ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
}

/*This is to apply to the case of cur - > Val < prev - > val,
Prev - > next = cur cannot be directly used to indicate the above situation */

while(cur){
if(sortedlist->val <= cur->val){
sortedlist = sortedlist->next;
}
else{
while(prev->next->val <= cur->val)
prev = prev->next;
sortedlist->next = cur->next;
cur->next = prev->next;
prev->next = cur;

}
cur = sortedlist->next;
}

}
};
```

The title is omitted.
Solution idea: the fast and slow pointers are placed on the head pointer respectively. The pace of the slow pointer is 1 and the pace of the fast pointer is 2. If there are rings in the linked list, the fast pointer will catch up with the slow pointer, and return true. If there are no rings in the linked list (including empty linked list), return false.

0141 problem solving

```/**
* struct ListNode {
*     int val;
*     ListNode *next;
*     ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
return false;
}

while(slow!=fast){
if(fast==NULL&&fast->next==NULL){
return false;
}
slow = slow->next;
fast = fast->next->next;
}
return true;

}
};

```

Application scope of linked list with inconsistent starting points:
Find the penultimate node in the linked list or delete the penultimate node in the linked list.

Application scope of linked list with inconsistent steps:
Find the middle node of the linked list, judge and detect whether there are links in the linked list, and find the intersection of the two linked lists.

Examples for the above two conclusions: 0019 and 0876 (omitted).

(0019) delete the penultimate node in the linked list
Title: give you a linked list, delete the penultimate node of the linked list, and return the head node of the linked list.

Solution idea: use speed pointers with different starting points. Place the fast pointer at the n nodes of the linked list first than the slow pointer, and then move the fast and slow pointers back at the same time until the fast pointer traverses to the end of the linked list (fast=NULL). At this time, the slow pointer just traverses to the penultimate node.

0019 problem solving

```/**
* struct ListNode {
*     int val;
*     ListNode *next;
*     ListNode() : val(0), next(nullptr) {}
*     ListNode(int x) : val(x), next(nullptr) {}
*     ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {

while(n){
fast = fast->next;
n -= 1;
}

while(fast){
fast = fast->next;
slow = slow->next;
}
slow->next = slow->next->next;

}
};
```

Title: give you the head nodes headA and headB of two single linked lists. Please find and return the starting node where the two single linked lists intersect. If the two linked lists do not have intersecting nodes, null is returned.

I didn't think of the correct way to solve this problem. After reading the answer, I felt that the way of thinking was very clever. Here I record the way of thinking. Here I write it in my own words below. Below is the official answer code.

0160 problem solution

```/**
* struct ListNode {
*     int val;
*     ListNode *next;
*     ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:

if(pA==nullptr||pB==nullptr){
return NULL;
}

while(pA != pB){