- 从尾到头输出链表
Question:输入一个链表的头结点,从尾到头反过来打印出每个节点的值。
典型的后进先出,可以使用栈实现。
12345678910111213141516void
Revers_Pring(ListNode* pHead)
{
std::stack<ListNode*> nodes;
ListNode* pNode = pHead;
while
(pNode != NULL)
{
modes.push(pNode);
pNode = pNode->pNext;
}
while
(!nodes.empty())
{
pNode = nodes.top();
printf
(
"%d\t"
,pNode->data);
nodes.pop();
}
}
递归本质上就是栈,所以也可以用递归实现
1234567891011void
ReversPrint(ListNode* pHead)
{
if
(pHead!=NULL)
{
if
(pHead->pNext != NULL)
{
ReversPrint(pHead->pNext);
}
printf
(
"%d\t"
,pHead->data);
}
}
- 在O(1)时间删除链表结点
题目:给定单向链表的头指针和一个节点指针,定义一个函数在O(1)时间删除该节点。
分析:O(1)时间内把下一个节点的内存复制覆盖掉要删除的节点,并删除下一个节点。对于尾结点,仍需要顺序查找,复杂度O(n)。
以下代码前提假设为要删除的结点确实在链表中。
1234567891011121314151617181920212223242526272829303132void
DeleteNode(ListNode** pHead,ListNode* pDelete)
{
if
(!pHead || !pDelete)
return
;
//要删除的节点不是尾节点
if
(pDelete->pNext!=NULL)
{
ListNode* Next = pDelete->pNext;
pDelete->data = Next->data;
pDelete->pNext = Next->pNext;
delete
Next;
Next = NULL;
}
//链表只有一个节点
else
if
(*pHead == pDelete)
{
delete
pDelete;
pDelete = NULL;
*pHead = NULL;
}
//链表中有多个节点,删除尾节点,需要顺序查找
else
{
ListNode *Node = *pHead;
while
(Node->pNext!=pDelete)
Node = Node->pNext;
Node->pNext = NULL;
delete
pDelete;
pDelete = NULL;
}
}
- 链表中的倒数第k个结点
题目:输入一个链表,输出该链表中倒数第k个结点。假设链表的尾节点为倒数第一个结点。
分析:两个指针差k-1步,但需要注意特殊情况:Head为空指针,结点数少于k个,参数k=0情况。
延伸:求链表中间结点。定义两个指针,一个指针一次一步,一个指针一次两步,走得快的到尾部时,走的慢的正好在中间。同样,判断单向链表是否形成了环形,也是这样,最后如果走得快的指针追上了走得慢的指针,那么链表就是环形链表,如果走得快的走到了链表尾部都没有追上慢的,那么就不是环形链表。
123456789101112131415161718192021ListNode* FindKthToTail(ListNode* pHead,
int
k)
{
if
(pHead == NULL || k < 0)
return
NULL;
ListNode* pA = pHead;
//先移动k-1步
ListNode* pB = pHead;
for
(
int
i = 0;i < k-1;++i)
{
if
(pA == NULL)
return
NULL;
else
pA = pA->pNext;
}
while
(pA->pNext!=NULL)
{
pA = pA->pNext;
pB = pB->pNext;
}
return
pB;
}
- 反转链表
题目:定义一个函数,输入一个链表的头指针,反转该链表并输出反转后链表的头结点。
分析:为防止链表断开,需定义三个指针,分别指向当前遍历到的结点、它的前一个结点及后一个结点。
12345678910111213141516ListNode* ReverseList(ListNode* pHead)
{
ListNode* ReversedHead = NULL;
ListNode* Node = pHead;
ListNode* Prev = NULL;
//头结点反转后指向NULL
while
(Node != NULL)
{
ListNode* Next = Node->pNext;
//指向后一个结点
if
(Next == NULL)
ReversedHead = Node;
Node->pNext = Prev;
Prev = Node;
Node = Next;
}
return
ReversedHead;
}
- 合并两个排序的链表
题目:输入两个递增排序的链表,合并这两个链表并使新链表中的结点仍然是按照递增排序的。
123456789101112131415161718ListNode* Merge(ListNode* pHead1,ListNode* pHead2)
{
if
(pHead1 == NULL)
return
pHead2;
if
(pHead2 == NULL)
return
pHead1;
ListNode* pMerge = NULL;
if
(pHead1->data < pHead2->data)
{
pMerge = pHead1;
pMerge->pNext=Merge(pHead1->pNext,pHead2);
}
else
{
pMerge = pHead2;
pMerge->pNext=Merge(pHead1,pHead2->pNext);
}
return
pMerge;
}
- 两个链表的第一个公共结点(还有树的公共结点问题)
题目:输入两个链表,找出它们的第一个公共结点。
分析:如果两个链表有公共结点,那么公共结点出现在两个链表的尾部。从两个尾部开始向前比较,最后一个相同的借点就是我们要找的结点。分别将两个链表的结点放入两个栈,每次比较栈顶结点,相同就弹出比较下一个。(需要复制空间)
或者我们先遍历一遍得到两个链表的长度,然后让长的链表先向前走几步,之后再同时遍历。
- 环形链表-圆圈中最后剩下的数字
题目:0,1,2,…n-1这n个数排成一个圆圈,从数字0开始每次从这个圆圈里删除第m个数字,求出这个圆圈中最后剩下的那个数字(约瑟夫问题)。例如,{0,1,2,3,4}从0开始删除第3个数字,那么删除的前四个数依次是2,0,4,1,最后剩下3.
解法一:环形链表模拟
用std::list模仿环形链表,扫描到链表尾部时记得吧迭代器移到头部。1234567891011121314151617181920212223242526int
LastRemain(unsigned
int
n,unsigned
int
m)
{
if
(n<1||m<1)
return
-1;
list<
int
> numbers;
for
(
int
i=0;i<n;++i)
numbers.push_back(i);
list<
int
>::iterator cur = numbers.begin();
while
(numbers.size()>1)
{
for
(
int
i=1;i<m;++i)
{
cur++;
if
(cur == numbers.end())
cur = numbers.begin();
}
list<
int
>::iterator next = ++cur;
if
(next == numbers.end())
next = numbers.begin();
--cur;
numbers.erase(cur);
cur=next;
}
return
*(cur);
}
解法二:分析每次被删除的数字的规律直接计算出最后剩下的数字
1) if we shift the ids by k, namely, start from k instead of 0, we should add the result by k%n
2) after the first round, we start from k+1 ( possibly % n) with n-1 elements, that is equal to an (n-1) problem
while start from (k+1)th element instead of 0, so the answer is (f(n-1, m)+k+1)%n
3) k = m-1, so f(n,m)=(f(n-1,m)+m)%n.
finally, f(1, m) = 0;Now this is a O(n) solution.
123456789int
LastRemain(unsigned
int
n,unsigned
int
m)
{
if
(n<1||m<1)
return
-1;
int
last=0;
for
(
int
i=2;i<=n;++i)
last = (last+m)%i;
return
last;
}
- 二叉搜索树与双向链表
题目:输入一颗二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建新的结点,只能调整树中节点指针的指向。分析:中序遍历,当遍历到根节点时,连接左子链表的最右结点和右子链表的最左结点。再递归调整左右子链表。
12345678910111213141516171819202122232425262728293031323334353637383940struct
BinaryTreeNode
{
int
nValue;
BinaryTreeNode* pLeft;
BinaryTreeNode* pRight;
};
void
helper(BinaryTreeNode *&head,BinaryTreeNode *&tail,BinaryTreeNode *root)
{
BinaryTreeNode *lt,*rh;
//left tail,right head
if
(root == NULL)
{
head = NULL;
tail = NULL;
return
;
}
helper(head,lt,root->pLeft);
helper(rh,tail,root->pRight);
if
(lt != NULL)
{
lt->pRight = root;
root->pLeft = lt;
}
else
head = root;
if
(rh != NULL)
{
root->pRight = rh;
rh->pLeft = root;
}
else
tail = root;
}
BinaryTreeNode* treeToLinkedList(BinaryTreeNode *root)
{
BinaryTreeNode *head,*tail;
//生成双向链表的头指针和尾指针
helper(head,tail,root);
return
head;
}
- 复杂链表的复制
题目:实现函数ComplexListNode* Clone(ComplexListNode* pHead),复制一个复杂链表。复杂链表中,每个结点除了有一个指针指向下一个结点,还有一个指针指向链表中任意结点或者NULL。
分析:
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465struct
ComplexNode
{
int
m_nValue;
ComplexNode* m_pNext;
ComplexNode* m_pSibling;
};
ComplexNode* Clone(ComplexNode* pHead)
{
if
(pHead == NULL)
return
NULL;
preClone(pHead);
inClone(pHead);
return
postClone(pHead);
}
void
preClone(ComplexNode* pHead)
{
//复制原始链表的任意结点N并创建新结点N’,链接到N的后面
ComplexNode* pNode = pHead;
while
(pNode != NULL)
{
ComplexNode* pClone =
new
ComplexNode();
pClone->m_nValue = pNode->m_nValue;
pClone->m_pNext = pNode->m_pNext;
pClone->m_pSibling = NULL;
pNode->m_pNext = pClone;
pNode = pClone->m_pNext;
}
}
void
inClone(ComplexNode* pHead)
{
//原始链表上的节点N的m_pSibling指向S,则N'指向S的下一个节点S'
ComplexNode * pNode = pHead;
while
(pNode != NULL)
{
ComplexNode* pClone = pNode->m_pNext;
if
(pNode->m_pSibling != NULL)
pClone->m_pSibling = pNode->m_pSibling->m_pNext;
pNode = pClone->m_pNext;
}
}
ComplexNode * postClone(ComplexNode* pHead)
{
//拆分链表,奇偶
ComplexNode* pNode = pHead;
ComplexNode* pCloneHead = NULL;
ComplexNode* pCloneNode = NULL;
if
(pNode != NULL)
{
pCloneHead = pCloneNode = pNode->m_pNext;
pNode->m_pNext = pCloneNode->m_pNext;
pNode = pNode->m_pNext;
}
while
(pNode != NULL)
{
pCloneNode->m_pNext = pNode->m_pNext;
pCloneNode = pCloneNode->m_pNext;
pNode->m_pNext = pCloneNode->m_pNext;
pNode = pNode->m_pNext;
}
return
pCloneHead;
}
- 从一个未排序的单链表中删除重复元素
题目:Write code to remove duplicates from an unsorted linked list.
解法一:如果对空间复杂度没有要求,则使用哈希表,如果存在即删除,如果不存在将值写入hashtable。
解法二:使用两个pointer进行遍历–current进行正常遍历,当runner每次从头开始查找(到current为止)是否有重复元素,如果重复,删除current。
1234567891011121314151617181920212223242526272829void
deleteDups(ListNode* pHead)
{
if
(pHead == NULL)
return
;
ListNode* pre = pHead;
ListNode* current = pre->pNext;
while
(current != NULL)
{
ListNode* runner = pHead;
while
(runner != current)
{
if
(runner->data == current->data)
{
//remove current
ListNode* tmp = current->pNext;
pre->pNext = tmp;
current = tmp;
break
;
//跳出的while循环
}
runner = runner->pNext;
}
if
(runner == current)
{
//runner在0-current间遍历
//无重复
pre = current;
current = current->pNext;
}
}
}
- You have two numbers represented by a linked list,where each node contains a single digit.The digits are stored in reverse order,such that the 1′s digit is at the head of the list.Write a function that adds the two numbers and returns the sum as a linked list.e.g. Input:(3->1->5),(5->9->2),Output:8->0->8
分析:每一位的值相当于(链表1的值+链表2的值+前一位的进位)%10,如果该位所得的值超过10,带进位。12345678910111213141516ListNode* addLists(ListNode* p1,ListNode* p2,
int
flag)
{
if
(p1==NULL && p2==NULL)
return
NULL;
ListNode* result;
int
value = flag;
if
(p1!=NULL)
value += p1->data;
if
(p2!=NULL)
value += p2->data;
result->data = value%10;
ListNode* more = addLists(p1 == NULL?NULL:p1->pNext,
p2==NULL?NULL:p2->pNext,
value>10?1:0);
result->pNext = more;
return
result;
}
- Given a circular linked list,implement an algorithm which returns node at the beginning of the loop.e.g. Input:A->B->C->D->E->C,output:C.
分析:两个指针,一个每次移动1步,一个每次移动2步,如果最后能相遇,则表明链表有环。
1)表头距离环开始处k个结点;2)p1p2相遇处距离环开始处也为k个结点;3)寻找两个点的中点即可。12345678910111213141516171819202122ListNode* FindBeginning(ListNode* pHead)
{
ListNode* p1 = pHead;
ListNode* p2 = pHead;
while
(p2->pNext!=NULL)
{
p1=p1->pNext;
p2=p2->pNext->pNext;
if
(p1==p2)
break
;
}
if
(p2->pNext==NULL)
return
NULL;
//no loop
p1 = pHead;
while
(p1!=p2)
{
p1=p1->pNext;
p2=p2->pNext;
}
return
p2;
}
数据结构面试题之一----链表
最新推荐文章于 2025-01-07 07:30:00 发布