直通BAT--数据结构与算法五(链表类)
来源:互联网 发布:辐射4优化补丁 编辑:程序博客网 时间:2024/04/29 02:52
链表题解题技巧:
- 链表调整函数的返回值类型,根据要求往往是节点类型;
- 处理链表的过程中,先采用画图的方式理清逻辑;
- 链表问题对于边界条件讨论要求严格;
- 最好不要原链表的基础上改;
- 链表赋值时,考虑链表头尾节点,当前节点的next指针是否要为NULL;
- 善用stack栈结构;
- node->next ==NULL与node == NULL之间的区别;
- node = node->next循环前提不要忘记。
链表插入和删除:
- 特殊处理链表为空,或者链长为1的情况;
- 注意插入操作的调整过程,前一个节点指向要插入的节点,要插入的节点指向下一个节点;
- 注意删除操作的调整过程,前一个节点指向下一个节点。
- 头节点和尾节点特殊考虑
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) : val(x), next(NULL) {}
};
1.链表节点插入
//给定链表的信息,及元素的值A及对应的nxt指向的元素编号同时给定val,请构造出这个环形链表,并插入该值。
//测试样例:
//[1, 3, 4, 5, 7], [1, 2, 3, 4, 0], 2
//返回:{ 1, 2, 3, 4, 5, 7 }
ListNode* InsertValue::insertValue(vector<int> A, vector<int> nxt, int val){
//创建插入值的节点
ListNode *insertNode = new ListNode(val);
//如果A为空
if (A.size() == 0){
insertNode->next = insertNode;
return insertNode;
}
//构建链表
ListNode *headNode = new ListNode(A[0]);
ListNode *listNode = headNode;
for (int i = 1; i < A.size(); ++i){
listNode->next = new ListNode(A[i]);
listNode = listNode->next;
}
listNode->next = headNode;
//插入的节点值小于原来的头节点
if (headNode->val >= val){
insertNode->next = headNode;
headNode = insertNode;
return headNode;
}
//构建两个节点,如果新插入的节点在这两个节点中间则插入
ListNode *preNode = headNode;
ListNode *curNode = headNode->next;
while (curNode != headNode){
if (preNode->val <= val && curNode->val >= val){
preNode->next = new ListNode(val);
preNode->next->next = curNode;
return headNode;
}
preNode = curNode;
curNode = curNode->next;
}
//新插入的节点比所有节点都大,则插入到最后
if (preNode->val <= val){
preNode->next = insertNode;
insertNode->next = headNode;
return headNode;
}
}
2.链表节点删除
//实现一个算法,删除单向链表中间的某个结点。
//给定带删除的头节点和要删除的数字,请执行删除操作,返回删除后的头结点。链表中没有重复数字
//删除链表节点:如果头节点就是,则删除;不是则循环扫描,扫描到节点则将前一个节点指向当前节点的后一个节点
ListNode* RemoveNode::removeNode(ListNode* pHead, int delVal){
if (pHead->val == delVal){
pHead = pHead->next;
return pHead;
}
ListNode *preNode = pHead;
ListNode *curNode = pHead->next;
while (curNode != NULL){
if (curNode->val == delVal){
preNode->next = curNode->next;
return pHead;
}
preNode = curNode;
curNode = curNode->next;
}
return pHead;
}
3.链表分化
//对于一个链表,我们需要用一个特定阈值完成对它的分化,使得小于等于这个值的结点移到前面,大于该值的结点在后面,同时保证两类结点内部的位置关系不变。
//给定一个链表的头结点head,同时给定阈值val,请返回一个链表,使小于等于它的结点在前,大于等于它的在后,保证结点值不重复。
//测试样例:
//{ 1, 4, 2, 5 }, 3
//{1, 2, 4, 5}
//链表分化:定义smallNode存放小于给定值的链表,largeNode存放大于给定值的链表;并初始化
//分别记录其头节点
//给smallNode与largeNode装值
//令largeNode->next=NULL;
//构成完整的链表
ListNode1* ListDivide::listDivide(ListNode* head, int val){
if (head == NULL || head->next == NULL)
return head;
ListNode *node = head;
ListNode *smallNode = new ListNode(0);
ListNode *smallNodeHead = smallNode;
ListNode *largeNode = new ListNode(0);
ListNode *largeNodeHead = largeNode;
while (node != NULL){
if (node->val <= val){
smallNode->next = node;
smallNode = smallNode->next;
}
else{
largeNode->next = node;
largeNode = largeNode->next;
}
node = node->next;
}
largeNode->next = NULL;
smallNode->next = largeNodeHead->next;
head = smallNodeHead->next;
return head;
}
4.链表查找公共值部分
/现有两个升序链表,且链表中均无重复元素。请设计一个高效的算法,打印两个链表的公共值部分。
//给定两个链表的头指针headA和headB,请返回一个vector,元素为两个链表的公共部分。请保证返回数组的升序。两个链表的元素个数均小于等于500。保证一定有公共值
//测试样例:
//{ 1, 2, 3, 4, 5, 6, 7 }, { 2, 4, 6, 8, 10 }
//返回:[2.4.6]
//链表的公共值部分:判断链表查找值
//相等则headA与headB找下一个节点
//headA值小于headB,则headA等于下一个节点
//headA值大于headB,则headB等于下一个节点
//直到headA与headB有一个为NULL
vector<int> FindCommonParts::findCommonParts(ListNode* headA, ListNode* headB){
vector<int> commonParts;
while (headA != NULL && headB != NULL){
if (headA->val == headB->val){
commonParts.push_back(headA->val);
headA = headA->next;
headB = headB->next;
}
else if (headA->val < headB->val){
headA = headA->next;
}
else{
headB = headB->next;
}
}
return commonParts;
}
5.K值逆序
//有一个单链表,请设计一个算法,使得每K个节点之间逆序,如果最后不够K个节点一组,则不调整最后几个节点。
//例如链表1->2->3->4->5->6->7->8->null,K = 3这个例子。调整后为,3->2->1->6->5->4->7->8->null。
//因为K == 3,所以每三个节点之间逆序,但其中的7,8不调整,因为只有两个节点不够一组。
//
//给定一个单链表的头指针head, 同时给定K值,返回逆序后的链表的头指针。
ListNode* KValueReverse::kValueReverse(ListNode* head, int k){
//head为NULL,或k为1直接返回
if (head == NULL || k == 1){
return head;
}
//遍历原链表
ListNode* curNode = head;
//记录每一逆序段的头
ListNode* headNode = head;
//记录每一逆序段的尾
ListNode* lastNode = new ListNode(0);
//记录逆序后的链表
ListNode* node = new ListNode(0);
//利用栈结构逆序
vector<ListNode*> listVector;
//计数判断
int count = 0;
//分离第一次头节点
int headFlag = 0;
while (curNode != NULL){
++count;
//入栈操作
listVector.push_back(curNode);
//k个节点满
if (count >= k){
//记录逆序段的尾
lastNode = curNode;
//记录下一个逆序部分的头
curNode = curNode->next;
//当前逆序部分的头尾均要设为NULL,防止链表成环
headNode->next = NULL;
lastNode->next = NULL;
//出栈操作
while (!listVector.empty()){
//特殊处理头节点
if (headFlag == 0){
head = listVector.back();
node = head;
listVector.pop_back();
headFlag = 1;
}
//处理之后的节点
else{
node->next = listVector.back();
node = node->next;
listVector.pop_back();
}
}
//记录下一逆序段的头
headNode = curNode;
count = 0;
continue;
}
//未达到k个节点则继续入栈
curNode = curNode->next;
}
//未满足k个节点,不逆序
node->next = headNode;
return head;
}
6.链表删除某个值的所有相等值
//现在有一个单链表。链表中每个节点保存一个整数,再给定一个值val,把所有等于val的节点删掉。
//
//给定一个单链表的头结点head,同时给定一个值val,请返回清除后的链表的头结点,保证链表中有不等于该值的其它值。请保证其他元素的相对顺序。
//
//测试样例:
//{ 1, 2, 3, 4, 3, 2, 1 }, 2
//{1, 3, 4, 3, 1}
//链表删除某个值的所有相等值:将所有不相等的值生成新的链表,最后为NULL
ListNode* ClearValue::clearValue(ListNode* head, int val){
if (head == NULL)
return head;
ListNode* resultHead = NULL;
ListNode* node = head;
ListNode* resultNode = NULL;
while (node != NULL){
if (node->val != val){
if (resultHead == NULL){
resultHead = node;
resultNode = resultHead;
}
else{
resultNode->next = node;
resultNode = resultNode->next;
}
}
node = node->next;
}
resultNode->next = NULL;
return resultHead;
}
7.链表回文
//请编写一个函数,检查链表是否为回文。
//给定一个链表ListNode* pHead,请返回一个bool,代表链表是否为回文。
//测试样例:
//{ 1, 2, 3, 2, 1 }
//返回:true
//{ 1, 2, 2, 1 }
//返回:true
//{ 1, 2, 3, 2, 3 }
//返回:false
//链表是否为回文:定义快慢指针,判断是否快指针到达链表尾:分为奇数偶数回文,慢指针入栈,比较后半部分与前半部分。
bool CheckPalindrome::checkPalindrome(ListNode* pHead){
//pHead为NULL
if (pHead == NULL){
return false;
}
//链表只有一个元素
if (pHead->next == NULL){
return true;
}
//定义快慢指针
ListNode* slowNode = pHead;
ListNode* fastNode = pHead;
vector<int> listVector;
listVector.push_back(pHead->val);
//判断是否快指针到达链表尾:分为奇数偶数回文
while (fastNode->next != NULL){
if (fastNode->next->next != NULL){
slowNode = slowNode->next;
listVector.push_back(slowNode->val);
fastNode = fastNode->next->next;
}
else{
slowNode = slowNode->next;
break;
}
}
//比较后半部分与前半部分
while (!listVector.empty()){
if (slowNode->val == listVector.back()){
slowNode = slowNode->next;
listVector.pop_back();
}
else{
return false;
}
}
return true;
}
8.链表判环
//如何判断一个单链表是否有环?有环的话返回进入环的第一个节点的值,无环的话返回 - 1。
//如果链表的长度为N,请做到时间复杂度O(N),额外空间复杂度O(1)。
//
//给定一个单链表的头结点head(注意另一个参数adjust为加密后的数据调整参数,方便数据设置,与本题求解无关),请返回所求值。
//链表判环:声明一个慢指针一个快指针,快指针走2格,慢指针走1格,直到二者相遇
//然后,快指针指向头节点,慢指针不动,二者循环移动一个节点,直到再次相遇就是入环的第一个点。
int CheckLoop::checkLoop(ListNode* head, int adjust){
if (head == NULL || head->next == NULL){
return -1;
}
if (head->next->next == NULL){
return -1;
}
if (head->next->next == head){
return head->val;
}
ListNode* slowNode = head->next;
ListNode* fastNode = head->next->next;
while (fastNode != NULL && fastNode->next != NULL){
if (slowNode == fastNode){
fastNode = head;
while (slowNode != fastNode){
slowNode = slowNode->next;
fastNode = fastNode->next;
}
return fastNode->val;
}
else{
slowNode = slowNode->next;
fastNode = fastNode->next->next;
}
}
return -1;
}
9.无环链表相交
//现在有两个无环单链表,若两个链表的长度分别为m和n,请设计一个时间复杂度为O(n + m),额外空间复杂度为O(1)的算法,
//判断这两个链表是否相交。
//给定两个链表的头结点headA和headB,请返回一个bool值,代表这两个链表是否相交。保证两个链表长度小于等于500。
//链表相交:判断最后一个节点是否一样
bool CheckIntersect::checkIntersect(ListNode* headA, ListNode* headB){
while (headA == NULL || headB == NULL){
return false;
}
while (headA->next != NULL){
headA = headA->next;
}
while (headB->next != NULL){
headB = headB->next;
}
if (headA == headB){
return true;
}
return false;
}
10.有环链表相交
ListNode* circleNode(ListNode* head);
//如何判断两个有环单链表是否相交?相交的话返回第一个相交的节点,不想交的话返回空。
//如果两个链表长度分别为N和M,请做到时间复杂度O(N + M),额外空间复杂度O(1)。
//
//给定两个链表的头结点head1和head2(注意,另外两个参数adjust0和adjust1用于调整数据, 与本题求解无关)。
//请返回一个bool值代表它们是否相交。
ListNode* circleNode(ListNode* head);
bool CheckCircleIntersection::checkCircleIntersection(ListNode* head1, ListNode* head2, int adjust0, int adjust1){
ListNode* circleNode1 = circleNode(head1);
ListNode* circleNode2 = circleNode(head2);
if (circleNode1 == NULL || circleNode2 == NULL){
return false;
}
//判断入环的节点是否相同,相同则在此节点前已相交,否则在环内相交或不想交
ListNode* node1 = head1;
ListNode* node2 = head2;
if (circleNode1 == circleNode2){
int count1 = 0;
int count2 = 0;
while (node1 != circleNode1){
++count1;
node1 = node1->next;
}
while (node2 != circleNode2){
++count2;
node2 = node2->next;
}
int temp = 0;
node1 = head1;
node2 = head2;
if (count1 > count2){
temp = count1 - count2;
while (temp-- > 0){
node1 = node1->next;
}
}
else{
temp = count2 - count1;
while (temp-- > 0){
node2 = node2->next;
}
}
while (node1 != node2){
node1 = node1->next;
node2 = node2->next;
}
//此时的node1与node2相等,为相交的第一个节点
return true;
}
//环内相交或不想交
else{
node1 = circleNode1->next;
while (node1 != circleNode1){
if (node1 == circleNode2){
//此时的node1与circleNode2相等,为相交的第一个节点
return true;
}
node1 = node1->next;
}
return false;
}
}
//判断链表是否有环
ListNode* circleNode(ListNode* head){
if (head == NULL){
return NULL;
}
ListNode* slowNode = head;
ListNode* fastNode = head;
while (fastNode != NULL && fastNode->next != NULL){
slowNode = slowNode->next;
fastNode = fastNode->next->next;
if (slowNode == fastNode){
fastNode = head;
while (slowNode != fastNode){
slowNode = slowNode->next;
fastNode = fastNode->next;
}
return fastNode;
}
}
return NULL;
}
阅读全文
0 0
- 直通BAT--数据结构与算法五(链表类)
- 直通BAT--数据结构与算法十(排列组合)
- 直通BAT--数据结构与算法十一(概率)
- 直通BAT--数据结构与算法六(二分搜索)
- 直通BAT--数据结构与算法七(二叉树)
- 直通BAT--数据结构与算法八(位运算)
- 直通BAT--数据结构与算法九(动态规划)
- 直通BAT面试算法---智力题2-赛马
- 直通BAT算法面试题总结
- 直通BAT面试算法精讲课
- 直通BAT算法精讲附程序源码
- 牛客网(直通BAT面试算法班)第四章 队列与栈 Day5
- 数据结构与算法五
- 牛客网-直通BAT面试算法精品课购买优惠码
- 优惠码:直通BAT面试算法精品课-牛客网
- 牛课网--直通BAT面试算法精讲课--优惠吗来啦
- 直通BAT面试算法---智力题1-涂色练习题
- 优惠码:牛客网-直通BAT面试算法精品课
- java分布式简单实现
- struts2中action跳往action
- liunx中虚拟机中的常使用运行命令
- 【PAT】【Advanced Level】1021. Deepest Root (25)
- (全套最新)在虚拟机ubuntu16.04下安装php环境,配置apache2的8080端口访问并在宿主windows7中访问
- 直通BAT--数据结构与算法五(链表类)
- CentOS7安装VNC(tigerVNC Server和tightVNC Viewer)
- okhttp与urlconnection连接网络
- 新手上路之oracle JDBC 笔记
- 数据结构导论思维导图
- OpenGL常用函数详解集锦
- 【剑指offer】面试题32:从上到下打印二叉树
- 选择排序
- 3——语音分析——物理架构