目录
- 链表结构
- 单链表和双链表
- 链表题目常用技巧
- 题目
- 面试题 02.06. 回文链表
- 给定一个数,把单链表划分为左边小于,中间相等,右边大的形式
- 138. 复制带随机指针的链表
- 单链表相交问题
- 补充:哈希表和有序表的简单介绍
链表结构
单链表和双链表
// 单链表
typedef struct Node {int val;struct Node *next;
} Node;// 双链表
typedef struct Node {int val;struct Node *pre;struct Node *next;
} Node;
链表题目常用技巧
- 额外数据结构记录(哈希表等)
- 快慢指针
题目
面试题 02.06. 回文链表
- 1->2->1具有回文结构,1->2->2->1具有回文结构,2->3->4不具有回文结构
普通解法:栈
高级解法:栈 + 快慢指针,只放链表后边一半的数据,这样可以节约一半的空间
O(1)空间复杂度解法:快慢指针使得慢指针指向中点,然后把链表右边逆序,再从头部和尾巴分别反方向遍历,判断是否回文,最后把链表恢复原状
给定一个数,把单链表划分为左边小于,中间相等,右边大的形式
- 面试题 02.04. 分割链表
- 普通解法:参考荷兰国旗和快排,把链表变成数组去做
高级解法:O(1)的时间复杂度,使用6个额外的链表节点指针,记录小于区,等于区和大于区
138. 复制带随机指针的链表
- 如果不考虑 random 指针的话,对一条链表进行拷贝,我们只需要使用两个指针:一个用于遍历原链表,一个用于构造新链表(始终指向新链表的尾部)即可。这一步操作可看做是「创建节点 + 构建 next 指针关系」。
https://leetcode.cn/problems/fu-za-lian-biao-de-fu-zhi-lcof/solution/by-ac_oier-6atv/
// 伪代码,用于说明正常复制链表的操作
Node t = head;
Node dummy = new Node(-1), cur = dummy;
while (head != null) {Node node = new Node(head.val);cur.next = node;cur = cur.next; // 始终指向新链表的尾巴head = head.next;
}
/*** Definition for a Node.* struct Node {* int val;* struct Node *next;* struct Node *random;* };*/typedef struct {void *key; // keyvoid *value;UT_hash_handle hh;
} HashTable;HashTable *g_hash;void HashAdd(void *cur, void *node)
{HashTable *tmp = NULL;HASH_FIND_PTR(g_hash, &cur, tmp); // 找if (tmp == NULL) {tmp = malloc(sizeof(HashTable));tmp->key = cur;tmp->value = node;HASH_ADD_PTR(g_hash, key, tmp);} else {printf("error\n");}
}struct Node* GetNode(void *cur)
{HashTable *tmp = NULL;HASH_FIND_PTR(g_hash, &cur, tmp);if (tmp != NULL) {return tmp->value;}return NULL;
}struct Node* copyRandomList(struct Node* head)
{g_hash = NULL;struct Node *cur = head;struct Node *curPlus = NULL;// 第一次遍历加入hash表中while (cur != NULL) {curPlus = malloc(sizeof(HashTable));curPlus->val = cur->val;curPlus->next = NULL;curPlus->random = NULL;HashAdd((void *)cur, (void *)curPlus);cur = cur->next;}// 第二次遍历建立新链表cur = head;while (cur != NULL) {GetNode((void *)cur)->next = GetNode((void *)(cur->next));GetNode((void *)cur)->random = GetNode((void *)(cur->random));cur = cur->next;}return GetNode(head);
}
单链表相交问题
补充:哈希表和有序表的简单介绍
- 哈希表在使用层面上可以理解为一种集合结构
- 有序表在使用层面上可以理解为一种集合结构,哈希表能做的事情有序表都能做,但是基于有序的前提,有序表可以提供更丰富的API
- 两者的区别是有序表把key按照顺序组织起来,而哈希表完全不组织
- 红黑树、AVL树、b树和跳表等都属于有序表,只是底层具体实现方式不同
分类 | c++名称 | 拷贝方式 | 描述 | 其他 |
---|---|---|---|---|
哈希表 | UnOrderedSet(UnSortedSet) | 普通数据类型都是值拷贝,对象是引用拷贝 | 只有key,没有伴随数据value | |
哈希表 | UnOrderedMa(UnSortedMap) | 普通数据类型都是值拷贝,对象是引用拷贝 | 只有key,又伴随数据value | |
有序表 | OrderedSet(SortedSet) | 普通数据类型都是值拷贝,对象则必须提供比较器,否则不知道如何按照key排序,依然是引用拷贝 | 只有key,没有伴随数据value | |
有序表 | OrderedMa(SortedMap) | 普通数据类型都是值拷贝,对象则必须提供比较器,否则不知道如何按照key排序,依然是引用拷贝 | 只有key,又伴随数据value |