链表测试框架示例:

 // leetcodeList.cpp : 定义控制台应用程序的入口点。vs2013 测试通过
// #include "stdafx.h"
#include <Windows.h>
#include <iostream> using namespace std; struct ListNode
{
int val;
ListNode *next;
ListNode(int x) : val(x), next(nullptr){};
}; void showList(ListNode *Head) {
ListNode *p = Head;
while (p != nullptr) {
cout << p->val << '\t';
p = p->next;
}
cout << endl;
} ListNode* createList(int n) {
ListNode dummy(-);
ListNode *prev = &dummy;
for (int i = ; i < n; ++i) {
int value;
cout << "input number:";
cin >> value;
prev->next = new ListNode(value);
prev = prev->next;
}
return dummy.next;
} ListNode* addTwoNumbers(ListNode *l1, ListNode *l2) {
ListNode *pa = l1;
ListNode *pb = l2;
ListNode dummy(-); // 头节点,目的是只有一个元素的时候不需要特殊考虑
ListNode *prev = &dummy;
int carry = ; // 表示进位
while (pa != nullptr || pb != nullptr) {
const int ai = (pa == nullptr ? : pa->val);
const int bi = (pb == nullptr ? : pb->val);
const int value = (ai + bi + carry) % ;
carry = (ai + bi + carry) / ;
prev->next = new ListNode(value); pa = pa->next;
pb = pb->next;
prev = prev->next;
}
if (carry > )
prev->next = new ListNode(carry);
return dummy.next;
} int _tmain(int argc, _TCHAR* argv[])
{
ListNode *l1 = createList();
showList(l1);
ListNode *l2 = createList();
showList(l2);
ListNode *result = addTwoNumbers(l1, l2);
showList(result);
system("pause");
return ;
}

listTestFrame

1, addTwoNumbers (思路同 数组题总结中的 plusOne 相似)

 ListNode* addTwoNumbers(ListNode *l1, ListNode *l2) {
ListNode *pa = l1;
ListNode *pb = l2;
ListNode dummy(-); // 头节点,目的是只有一个元素的时候不需要特殊考虑
ListNode *prev = &dummy;
int carry = ; // 表示进位
while (pa != nullptr || pb != nullptr) {
const int ai = (pa == nullptr ? : pa->val);
const int bi = (pb == nullptr ? : pb->val);
const int value = (ai + bi + carry) % ;
carry = (ai + bi + carry) / ;
prev->next = new ListNode(value); pa = pa->next;
pb = pb->next;
prev = prev->next;
}
if (carry > )
prev->next = new ListNode(carry);
return dummy.next;
}

addTwoNumbers

2,reverseBetween

 ListNode* reverseBetween(ListNode *head, int m, int n) {
ListNode dummy(-);
dummy.next = head; ListNode *prev = &dummy;
for(int i = ; i < m-; ++i) {
prev = prev->next; // prev 指向第 m 个位置之前的元素
}
ListNode * head2 = prev; prev = head2->next;
ListNode *cur = prev->next; // cur 指向要执行头插操作的节点
for (int i = m; i < n; ++i) { // 头插的元素个数为 n-m 个
prev->next = cur->next;
cur->next = head->next; // 头插法,从要反转位置的下一个元素进行头插
head->next = cur; cur = prev->next;
}
return dummy.next;
}

reverseBetween

3,partition List

 ListNode* partition1(ListNode* head, int x) {  // *******这个方法特别好用*******
ListNode left_dummy(-); // 定义小于3 的链表头节点
ListNode right_dummy(-); // 定义大于等于3 的链表头节点 auto left_cur = &left_dummy;
auto right_cur = &right_dummy; for (ListNode *cur = head; cur != nullptr; cur = cur->next) {
if (cur->val < x) {
left_cur->next = cur;
left_cur = cur;
}
else
{
right_cur->next = cur;
right_cur = cur;
}
}
left_cur->next = right_dummy.next;
right_cur->next = nullptr; return left_dummy.next;
} ListNode* partition2(ListNode *head, int x) {
if (head == nullptr) return head;
ListNode dummy(-);
dummy.next = head; ListNode *prev = &dummy;
for (ListNode *curr = head; curr->next != nullptr; curr = curr->next) { //对每一个元素进行判断,是否需要类头插
while (curr->next != nullptr)
{
if (curr->val < x)
{
prev = curr; // prev 始终指向最后一个小于 3 的节点,在此之后插入值小于 3 的节点
curr = curr->next;
}
else
{
break;;
}
}
ListNode *prev_last = curr; // 找到下一个要头插的节点
ListNode *last = curr->next;
while (last->next != nullptr)
{
if (last->val >= ) {
prev_last = last;
last = last->next;
}
else
{
break;
}
}
prev_last->next = last->next; // 在最后一个小于 3 的元素之后插入
last->next = prev->next;
prev->next = last; // 每次交换之后 curr 是指向最后一个大于等于 3 的节点,在此之前插入后面小于 3 的节点
}
return dummy.next;
}

partition

4, deleteDuplicates(I)

 // ***********方法1*********************
ListNode* deleteDuplicates1(ListNode *head) {
if (head == nullptr) return head;
ListNode dummy(head->val + ); // 保证不和 head->val 相同即可
dummy.next = head; ListNode *prev = &dummy;
while (head != nullptr) // head 指向后一个值,只要 head 有值,就要进行比较
{
if (prev->val == head->val) {
prev->next = head->next;
delete head; // 注意内存泄漏,删除的节点要释放内存,temp 指向要删除的节点
head = prev->next; // 此时 head 为一个野指针,可以重新赋值 }
else {
prev = head;
head = head->next;
}
}
return dummy.next;
} // ***********方法2*********************
void recur(ListNode *prev, ListNode *cur) {
if (cur == nullptr) return; if (prev->val == cur->val) {
prev->next = cur->next;
delete cur;
recur(prev, prev->next);
}
else {
recur(prev->next, cur->next);
}
}
ListNode* deleteDuplicates2(ListNode *head) { // 递归版本
if (!head) return head;
ListNode dummy(head->val + ); // 理由同上
dummy.next = head; recur(&dummy, head); // 前一个和后一个
return dummy.next;
} // ***********方法3*********************
ListNode* deleteDuplicates3(ListNode *head){ // 迭代版本,基本思想和 deleteDuplicates1 一样
if (head == nullptr) return nullptr; for (ListNode *prev = head, *curr = head->next; curr != nullptr; curr = prev->next) {
if (prev->val == curr->val) {
prev->next = curr->next;
delete curr; // 删除了 curr,系统并不会把 curr 设为空指针,而是还指向原来已经释放空间的内存地址
}
else {
prev = curr;
}
}
return head;
}

deleteDuplicates

deleteDuplicates(II)

 ListNode* deleteDuplicatesII1(ListNode *head) {  // 迭代版本
if (head == nullptr) return head;
ListNode dummy(-);
// dummy.next = head; ListNode *prev = &dummy;
ListNode *curr = head;
while (curr != nullptr)
{
bool duplicated = false;
while (curr->next != nullptr && curr->val == curr->next->val) {
duplicated = true;
ListNode *temp = curr;
curr = curr->next;
delete temp;
}
if (duplicated) { // 已经有重复元素,需要删除重复元素的最后一个元素
ListNode *temp = curr;
curr = curr->next;
delete temp;
continue; // 继续检查下一个元素,重新回到起点判断。
}
prev->next = curr;
prev = prev->next;
curr = curr->next;
}
prev->next = curr;
return dummy.next;
} ListNode* deleteDuplicatesII2(ListNode *head) { // 递归版本
if (!head || head->next) return head; ListNode *p = head->next;
if (head->val == p->val) {
while (p && head->val == p->val) {
ListNode *tmp = p;
p = p->next;
delete tmp;
}
delete head;
return deleteDuplicatesII2(p);
}
else {
head->next = deleteDuplicatesII2(head->next);
return head;
}
}

deleteDuplicates

5, rotate List

 ListNode* rotateRight(ListNode *head, int k) {
if (head == nullptr || k == ) return head; int len = ;
ListNode *p = head;
while (p->next != nullptr) { // 求链表长度
++len;
p = p->next;
}
k = len - k % len;
p->next = head;
for (int i = ; i < k; ++i) { // head 向后移动 k-1 步 | p 向右移动 k 步
head = head->next;
}
p = head; // 重新使用 p 指针
head = head->next;
p->next = nullptr;
return head;
}

rotateRight

6, remove Nth Node From End of List

 ListNode* removeNthFromEnd(ListNode *head, int n) {
if (head == nullptr) return head;
ListNode dummy(-);
dummy.next = head;
ListNode *first = &dummy;
ListNode *last = &dummy;
for (int i = ; i < n; ++i) { // 利用前后指针
last = last->next;
}
while (last->next != nullptr) {
first = first->next;
last = last->next;
}
ListNode *temp = first->next;
first->next = first->next->next;
delete temp;
return dummy.next;
}

removeNthFromEnd

7, Swap Nodes in Pairs

 ListNode* swapPairs1(ListNode *head) {
if (!head || !head->next) return head;
ListNode *p = head;
ListNode dummy(-);
dummy.next = head->next; // 直接指向新的头节点
ListNode *prev = &dummy; while (p && p->next) {
prev->next = p->next;
ListNode *temp = p->next->next;
p->next->next = p;
p->next = temp;
prev = p;
p = temp;
}
return dummy.next;
} ListNode* swapPairs2(ListNode *head) {
ListNode* p = head;
while (p && p->next) {
swap(p->val, p->next->val);
p = p->next->next;
}
return head;
}

swapPairs

8, Reverse Nodes in k-Group

 ListNode* reverseKGroup(ListNode *head, int k) {
if (!head ||!head->next || k <= ) return head;
ListNode dummy(-);
dummy.next = head;
ListNode *prev = &dummy;
bool enough = true; while (true) {
ListNode *p = head;
ListNode *begin = head;
for (int i = ; i < k; ++i) {
if (p) p = p->next;
else {
enough = false;
prev->next = begin; // 把最后不够反转的节点连接起来
return dummy.next;
}
}
ListNode *prev_next = begin;
if (enough) {
for (int i = ; i < k; ++i) { // 头插法
ListNode* temp = begin->next;
if (i == ) begin->next = nullptr; // 如果是最后一个节点,就把该节点的 next 置为 nullptr ,为了 showList 函数能展示
else begin->next = prev->next;
prev->next = begin;
begin = temp;
}
}
// showList(dummy.next); // using test
prev = prev_next;
head = begin;
}// while
}

reverseKGroup

9,  Linked List Cycle

 bool hasCycle1(ListNode *head) {  // STL::unordered_map
unordered_map<ListNode*, bool> visted; // 检测节点地址是否重复访问
for (head; head != nullptr; head = head->next) {
if (visted.find(head) != visted.end()) {
visted.find(head)->second = true; // 有没有都可以
return false;
}
else {
visted.find(head)->second = false;
}
}
return true;
} bool hasCycle2(ListNode *head) {
ListNode *slow = head;
ListNode *fast = head;
while (fast && fast->next) {
slow = slow->next; // slow 每次走一步
fast = fast->next->next; // fast 每次走两步,看作 fast 追 slow 的话,每次距离缩短 1 ,不会跳过slow的
if (slow == fast)
return true;
}
return false;
}

hasCycle

Linked List Cycle(II)

 ListNode* detectCycle1(ListNode *head) {  //  STL::unordered_map
unordered_map<ListNode*, bool> visted;
for (head; head != nullptr; head = head->next) {
if (visted.find(head) != visted.end()) {
return head;
}
else {
visted.find(head)->second = false;
}
}
return nullptr;
} ListNode* detectCycle2(ListNode *head) {
ListNode* slow = head;
ListNode* fast = head; while (fast && fast->next) {
slow = slow->next;
fast = fast->next->next;
if (slow == fast) {
ListNode *p = head;
while (p != slow) { // 思路来源:https://blog.csdn.net/xy010902100449/article/details/48995255
slow = slow->next;
p = p->next;
}
return p;
}
}
return nullptr;
}

detectCycle

10, Reorder List

 ListNode* reverse(ListNode *head) {
if (!head || !head->next) return head;
ListNode dummy(-);
dummy.next = head; ListNode *prev = &dummy;
ListNode *curr = head;
while (curr) {
ListNode* temp = curr->next; // 保存下一个节点
if (curr == head) curr->next = nullptr; // 头插法
else curr->next = prev->next;
prev->next = curr;
curr = temp;
}
return dummy.next;
} ListNode* mergeList(ListNode *list1, ListNode *list2) { // 把 list2 合并到 list1 中
if (!list1) return list2;
if (!list2) return list1; ListNode *curr1 = list1;
ListNode *curr2 = list2;
ListNode *temp1 = nullptr;
ListNode *temp2 = nullptr;
while (curr1->next && curr2->next) {
temp1 = curr1->next;
temp2 = curr2->next;
curr2->next = curr1->next;
curr1->next = curr2;
curr1 = temp1;
curr2 = temp2;
}
if (!curr1->next) // 如果第一个链表节点少,需要把长的链表后面的节点链接上,如果第二个少,不需要做处理
curr1->next = temp2;
return list1;
} ListNode* reorderList(ListNode *head) { // 先反转后半部分链表,然后再交互合并两个链表
if (!head || !head->next) return head; ListNode *slow = head;
ListNode *fast = head;
ListNode *prev = nullptr; while (fast && fast->next) {
prev = slow; // prev 后面断开,slow 指向后半链表的第一个节点
slow = slow->next;
fast = fast->next->next;
}
prev->next = nullptr;
ListNode *head2 = reverse(slow); // merge two lists head && head2
head = mergeList(head, head2); // 把 head2 合并到 head 中
return head;
}

reorderList

11, LRU Cache

 class LRUCache {
private:
struct CacheNode {
int key;
int value;
CacheNode(int k, int v) : key(k), value(v) {};
};
public:
LRUCache(int capacity) {
this->capacity = capacity;
}
int get(int key) {
if (cacheMap.find(key) == cacheMap.end()) return -; cacheList.splice(cacheList.begin(), cacheList, cacheMap[key]); // 移动最新访问的节点到最前面
cacheMap[key] = cacheList.begin(); // 更新 map 中节点的地址
return cacheMap[key]->value;
}
void set(int key, int value) {
if (cacheMap.find(key) == cacheMap.end()) { // 没有该元素
if (cacheList.size() == capacity) { // 空间已满
cacheMap.erase(cacheList.back().key);
cacheList.pop_back();
}
// 空间不满,插入新节点到链表头部
cacheList.push_front(CacheNode(key, value));
cacheMap[key] = cacheList.begin();
}
else { // 存在该元素,更新节点值,并把该节点放到链表头部,更新 cacheMap 中的值
cacheMap[key]->key = value;
cacheList.splice(cacheList.begin(), cacheList, cacheMap[key]);
cacheMap[key] = cacheList.begin();
}
}
private:
list<CacheNode> cacheList;
unordered_map<int, list<CacheNode>::iterator> cacheMap;
int capacity;
};

LRU Cache

12, deep Copy

 RandomListNode* copyRandomList1(RandomListNode *head) { // STL::unordered_map
if (head == nullptr) return nullptr; RandomListNode dummy(-);
RandomListNode *scan = &dummy;
RandomListNode *curr = head;
unordered_map<RandomListNode*, RandomListNode*> mapping; while (curr != nullptr) {
scan->next = new RandomListNode(curr->label);
mapping.insert(curr, scan->next); // 存储 原链表节点和复制链表节点的对应关系
curr = curr->next;
scan = scan->next;
}
curr = head;
scan = &dummy;
while (curr != nullptr) { // 赋值各个节点的 random 域
scan->next->random = mapping[curr->random];
curr = curr->next;
scan = scan->next;
}
return dummy.next;
} RandomListNode* copyRandomList2(RandomListNode *head) {
if (head == nullptr) return head; RandomListNode *scan = head;
while (!scan) { // step1: 第一遍扫描,对每个节点赋值
RandomListNode *newNode = new RandomListNode(scan->label);
newNode->next = scan->next;
scan->next = newNode;
scan = newNode->next;
}
scan = head; // step2: 第2遍扫描,对每个复制节点的 random 域进行赋值
while (!scan) {
if (!scan->random) {
scan->next->random = scan->random->next; // 把前面复制节点的 random 指向后面复制节点的 random
}
}
RandomListNode *newHead = head->next;
scan = head; // step3:第3遍扫描,拆分奇偶节点,分成两个链表,奇数组成的链表为原链表,偶数组成的链表为复制链表
while (!scan) {
RandomListNode *evenNode = scan->next;
scan->next = evenNode->next;
if (scan->next != nullptr) {
evenNode->next = scan->next->next;
}
scan = scan->next;
}
return newHead;
}

copyRandomList

以上题目来源于:https://github.com/soulmachine/leetcode(leetcode-cpp.pdf)

leetcode 链表类型题总结的更多相关文章

  1. leetcode 字符串类型题

    1,Vaild Palindrome bool isPalindrome(string& s) { transform(s.begin(), s.end(), s.begin(), tolow ...

  2. leetcode 树类型题

    树的测试框架: // leetcodeTree.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include <iostream& ...

  3. leetcode 链表类型题目解题总结

    最基础的方式要做到非常熟练,要熟练到不思考就能写,但又需明白各处的要求和陷阱 合并两个有序链表的操作,在前面加上一个初始节点,注意while循环和退出时的处理,理解如何处理其中一个链表遍历完的情况 L ...

  4. leetcode 数组类型题总结

    1,removeDuplicates(I) int removeDuplicatesI(vector<int>& nums){ // 重新组织数组,同 removeDuplicat ...

  5. leetcode 数组类型题

    // ConsoleApplication1.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include <Windows.h& ...

  6. LeetCode链表简单题

    一.21合并两个有序链表 代码如下: class Solution: def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNod ...

  7. leetcode 动态规划类型题

    1,Triangle int mininumTotal(vector<vector<int>>& triangle) { ; i >= ; --i) { ; j ...

  8. 【python】Leetcode每日一题-旋转链表

    [python]Leetcode每日一题-旋转链表 [题目描述] 给你一个链表的头节点 head ,旋转链表,将链表每个节点向右移动 k 个位置. 示例1: 输入:head = [1,2,3,4,5] ...

  9. 【python】Leetcode每日一题-删除排序链表中的重复元素

    [python]Leetcode每日一题-删除排序链表中的重复元素 [题目描述] 存在一个按升序排列的链表,给你这个链表的头节点 head ,请你删除所有重复的元素,使每个元素 只出现一次 . 返回同 ...

随机推荐

  1. iOS基础知识之属性及属性关键字

    iOS属性及属性关键字 一.属性功能:1.给现有的成员变量生成一对setter/getter方法.2.如果没有声明成员变量,自动声明一个_属性名的私有变量(默认的成员变量是受保护的). 二.属性关键字 ...

  2. webform(复合控件)

    一.组合单选 RadioButtonList 单选按钮与简单控件不同,可理解为在集合中放置多对象 例: <asp:RadioButtonList ID="RadioButtonList ...

  3. php多图片上传。

    1. <form method="post" enctype="multipart/form-data" action='请求地址' > <i ...

  4. svn分支

    在svn上我们除过一般的保存文档外,对于开发source,可以使用 trunk(主线),branch(分线), tag(上线或测试用) 做分支应用开发. trunk上建立代码位置,存放代码. 点击Te ...

  5. ReentrantLock 学习笔记

    有篇写的很不错的博客:https://blog.csdn.net/aesop_wubo/article/details/7555956    基于JDK1.8 参考着看源码 ,弄清楚lock()和un ...

  6. Servlet基本_WAR、デプロイ

    1.WAR.パッケージングWARはWeb Aplication Resourcesの略で.Webアプリに必要なファイルを1つのファイルにまとめて圧縮したものです.(日本では「わー」と発音の人が多い)W ...

  7. Lazarus 中文汉字解决方案

    使用Lazarus不得不面对编码问题,尤其中文.Lazarus使用的是UTF8编码,而很多windows程序使用的是ANSI编码,编码问题在此不多说大家可以google去. ANSI数据库与Lazar ...

  8. 剑指offer例题——旋转数组的最小数字

    题目:把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转. 输入一个非减排序的数组的一个旋转,输出旋转数组的最小元素. 例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转, ...

  9. LeetCode OJ 19. Remove Nth Node From End of List

    Given a linked list, remove the nth node from the end of list and return its head. For example, Give ...

  10. WINDOWS之CMD命令

    用法 1.切换盘符 2.切换到指定盘符后 在使用命令 cd +路径 一般介绍DOS命令,切换工作目录都是用CD命令,但是我在win7下的DOS中使用CD D:\却一直无法转到D盘. 后来在网上查找,发 ...