前言
链表本身不难,但是题目不一定能做对...
这基本上是一个 例题贴
目前打算每一部分都写三章: 基础贴,例题贴和刷题贴
题目一:快慢指针
输入链表的头节点,奇数长度请返回中点,偶数长度请返回下中点
解法一:数组法!
很容易,先把链表中的数据倒入数组中去,然后遍历数组看数组的size
直接coding
int midReturn(struct Node* head) {
struct Node* p = head;
int n = 0;
while (p != NULL) { // 计算链表长度
p = p->next;
n++;
}
int* arr = (int*)malloc(n * sizeof(int)); // 创建一个长度为n的数组
p = head;
int i = 0;
while (p != NULL) { // 将链表元素存储到数组中
arr[i++] = p->value;
p = p->next;
}
int mid;
if (n % 2 == 0) { // 如果链表长度为偶数,则返回下中间元素
mid = arr[n / 2 - 1];
}
else { // 如果链表长度为奇数,则返回中间元素
mid = arr[n / 2];
}
free(arr); // 释放数组的内存
return mid;
}
这种方式很容易,但是问题在于:额外空间复杂度较高,所以就可以用到快慢指针的方式
解法二:快慢指针
int midReturn(struct Node* head){
struct Node* slow = head; // 慢指针一次走一步
struct Node* fast = head; //快指针一次走两步
//一旦快指针到头了,就返回慢指针的位置
while(fast != NULL && fast !=NULL){
slow = slow->next;
fast = fast->next->next;
}
return slow->value;
}
代码easy且额外空间复杂度较小,仅为O(1)
题目二:判断是否回文
回文意思就是
1 2 3 2 1
a b c b a
谁系怀思怀系谁(假装有文化,实际上上网查的
判断一个结构是不是回文结构
解法一:栈方法
头节点开始遍历... 放进栈中去,再依次弹出
coding
// 实现一些栈的基本功能
struct stackNode{
char data;
struct stackNode* next;
};
struct Stack{
struct stackNode* top;
}
void push(struct Stack* stack, char data){
struct Node* newnode = (struct Node*)malloc(sizeof(struct Node));
newnode-> data = data;
newnode-> next = stack->top;
stack-> top = newnode;
}
char pop(struct Stack* stack){
if(stack->top == NULL){
return NULL;
}
int data = stack->top->data;
struct stackNode* temp = stack->top;
stack->top = stack->top->next;
free(temp);
return data;
}
//实现主功能
bool huwen(char* str[]){
int len = strlen(str[0]);
struct Stack* stack = NULL;
for(int i = 0; i < len; i++){
push(&stack, str[0][i]);
}
for(int j = 0; j < len; j++){
if(str[0][j] == pop(&stack)){
continue;
}
else{
printf("Error");
return 0;
}
}
return 1;
}
题目三:random指针
题目是这样的,链表的节点中现在除了next指针之外多了一个random指针,可能随机指向任意节点,也可能指向NULL。
给定一个这种带random指针类型的头节点,实现一个函数完成链表的复制,并返回赋值的新链表的head节点
解法一:哈希表
用Hashmap的方式,复制每一个节点放在hashmap中,然后再重构
#include"uthash.h"
struct ListNode{ // 先定义listnode 其中比常规节点多了一个random指针
int value;
struct ListNode* next;
struct ListNode* random;
};
struct HashTableNode{ // 定义hashtable 其中key和value都是listnode类型
// 因为要靠节点找到节点
struct ListNode* key;
struct ListNode* value;
UT_hash_handle hh;
};
struct ListNode* copyRandomList(struct ListNode* head){
if(head ==NULL){ //判断空
return NULL;
}
struct HashTableNode* hashmap = NULL; // 建一个空的hashmap
struct ListNode* newHead = (struct ListNode*)malloc(sizeof(struct ListNode));
struct ListNode* curNode = head;
struct ListNode* newNode = newHead;
while(curNode != NULL){
newNode->value = curNode->value;
newNode->next = curNode->next;
newNode->random = NULL;
struct HashTableNode *hashNode = (struct HashTableNode *)malloc(sizeof(struct HashTableNode));
hashNode->key = curNode; // 这样找到curnode就能找到newnode了
hashNode->value = newNode;
HASH_ADD_PTR(hashmap, key, hashNode);
curNode = curNode->next;
if(curNode != NULL){
newNode->next = (struct ListNode*)malloc(sizeof(struct ListNode));
newNode = newNode->next;
}
}
newNode->next = NULL; // 对新链表的尾节点的next指针赋值为NULL
curNode = head;
newNode = newHead;
while (curNode) {
if (curNode->random) {
struct HashTableNode *hashNode;
HASH_FIND_PTR(hashmap, &(curNode->random), hashNode);
newNode->random= hashNode->value;
}
curNode = curNode->next; // 将变量名改为curNode
newNode = newNode->next;
}
// 释放哈希表中的节点
struct HashTableNode *tmp, *hashNode;
HASH_ITER(hh, hashmap, hashNode, tmp) {
HASH_DEL(hashmap, hashNode);
free(hashNode);
}
// 释放链表节点和头节点
curNode = newHead;
while (curNode) {
struct ListNode* tmp = curNode;
curNode = curNode->next;
free(tmp);
}
return newHead;
}
题目四:判断链表是否有环
给定两个可能有环也可以无环的单链表,头节点head1和head2 。判断两节点是否相交,若相交返回第一个交点,不相交返回NULL
HASHMAP!
把链表从头开始遍历,每次都存进hashmap中。
然后查询,如果有重复,就说明形成了环
又有一个问题:如果存在hashmap里,value值应该对应啥?
key已经对应节点了,value没用啊
那就直接少开辟点空间,用hashset
#include "uthash.h"
struct ListNode {
int val;
struct ListNode *next;
};
struct HashSet{
struct ListNode* key;
UT_hash_handle hh;
};
struct ListNode* returnNode(struct ListNode* head1, struct ListNode* head2){
if(struct ListNode* head1 =NULL || struct ListNode* head2 = NULL){
return NULL;
}
struct HashSet* hashset = NULL;// 先初始化一个hashset
struct ListNode* p = head1;
while(p->next != NULL){
struct HashSet* hashNode = (struct HashSet*)malloc(sizeof(struct HashSet));
hashNode -> key = p;
HASH_ADD_PTR(hashset, key, hashNode);
p = p->next;
}
p = head2;
while(p != NULL){
struct HashSet* hasNode;
HASH_FIND_PTR(hashset, &(p), hashNode);
if(hashNode != NULL){
return hashNode->key;
}
p = p->next;
}
return NULL;
}