// 面试题23:链表中环的入口结点
// 题目:一个链表中包含环,如何找出环的入口结点?例如,在图3.8的链表中,
// 环的入口结点是结点3。
ListNode* FindFirstNode(ListNode* HeadNode) { if(!HeadNode) return nullptr; ListNode* FastNode = HeadNode; ListNode* SlowNode = HeadNode; while(FastNode&(FastNode->NextPoint)) { SlowNode = SlowNode->NextPoint; FastNode = SlowNode->NextPoint; if(FastNode == SlowNode) { SlowNode = HeadNode; while(FastNode != SlowNode) { FastNode = FastNode->NextPoint; SlowNode = SlowNode->NextPoint; } return SlowNode; } } return nullptr; }
//找到链表中环形链表的入口点
ListNode* FindTheFirstNode(ListNode* Node)
{
if(Node ==nullptr)
return nullptr;
ListNode* Fastp = Node;
ListNode Slowp = Node;
while((Fastp!= Slowp)&(Fastp!=nullptr))
{
Fastp = Fastp->NextPoint->NextPoint;
Slowp = Slowp->NextPoint;
}
Slowp =Node;
while(SLowp != Fastp)
{
Slowp = Slowp->NextPoint;
Fastp = Fastp->NextPoint;
}
return slowp;
}
// 面试题22:链表中倒数第k个结点
// 题目:输入一个链表,输出该链表中倒数第k个结点。为了符合大多数人的习惯,
// 本题从1开始计数,即链表的尾结点是倒数第1个结点。例如一个链表有6个结点,
// 从头结点开始它们的值依次是1、2、3、4、5、6。这个链表的倒数第3个结点是
// 值为4的结点。
#include <cstdio> #include "..\Utilities\List.h" ListNode* FindKthToTail(ListNode* pListHead, unsigned int k) { if(pListHead == nullptr || k == 0) return nullptr; ListNode *pAhead = pListHead; ListNode *pBehind = nullptr; for(unsigned int i = 0; i < k - 1; ++ i) { if(pAhead->m_pNext != nullptr) pAhead = pAhead->m_pNext; else { return nullptr; } } pBehind = pListHead; while(pAhead->m_pNext != nullptr) { pAhead = pAhead->m_pNext; pBehind = pBehind->m_pNext; } return pBehind; } // ====================测试代码==================== // 测试要找的结点在链表中间 void Test1() { printf("=====Test1 starts:=====\n"); ListNode* pNode1 = CreateListNode(1); ListNode* pNode2 = CreateListNode(2); ListNode* pNode3 = CreateListNode(3); ListNode* pNode4 = CreateListNode(4); ListNode* pNode5 = CreateListNode(5); ConnectListNodes(pNode1, pNode2); ConnectListNodes(pNode2, pNode3); ConnectListNodes(pNode3, pNode4); ConnectListNodes(pNode4, pNode5); printf("expected result: 4.\n"); ListNode* pNode = FindKthToTail(pNode1, 2); PrintListNode(pNode); DestroyList(pNode1); } // 测试要找的结点是链表的尾结点 void Test2() { printf("=====Test2 starts:=====\n"); ListNode* pNode1 = CreateListNode(1); ListNode* pNode2 = CreateListNode(2); ListNode* pNode3 = CreateListNode(3); ListNode* pNode4 = CreateListNode(4); ListNode* pNode5 = CreateListNode(5); ConnectListNodes(pNode1, pNode2); ConnectListNodes(pNode2, pNode3); ConnectListNodes(pNode3, pNode4); ConnectListNodes(pNode4, pNode5); printf("expected result: 5.\n"); ListNode* pNode = FindKthToTail(pNode1, 1); PrintListNode(pNode); DestroyList(pNode1); } // 测试要找的结点是链表的头结点 void Test3() { printf("=====Test3 starts:=====\n"); ListNode* pNode1 = CreateListNode(1); ListNode* pNode2 = CreateListNode(2); ListNode* pNode3 = CreateListNode(3); ListNode* pNode4 = CreateListNode(4); ListNode* pNode5 = CreateListNode(5); ConnectListNodes(pNode1, pNode2); ConnectListNodes(pNode2, pNode3); ConnectListNodes(pNode3, pNode4); ConnectListNodes(pNode4, pNode5); printf("expected result: 1.\n"); ListNode* pNode = FindKthToTail(pNode1, 5); PrintListNode(pNode); DestroyList(pNode1); } // 测试空链表 void Test4() { printf("=====Test4 starts:=====\n"); printf("expected result: nullptr.\n"); ListNode* pNode = FindKthToTail(nullptr, 100); PrintListNode(pNode); } // 测试输入的第二个参数大于链表的结点总数 void Test5() { printf("=====Test5 starts:=====\n"); ListNode* pNode1 = CreateListNode(1); ListNode* pNode2 = CreateListNode(2); ListNode* pNode3 = CreateListNode(3); ListNode* pNode4 = CreateListNode(4); ListNode* pNode5 = CreateListNode(5); ConnectListNodes(pNode1, pNode2); ConnectListNodes(pNode2, pNode3); ConnectListNodes(pNode3, pNode4); ConnectListNodes(pNode4, pNode5); printf("expected result: nullptr.\n"); ListNode* pNode = FindKthToTail(pNode1, 6); PrintListNode(pNode); DestroyList(pNode1); } // 测试输入的第二个参数为0 void Test6() { printf("=====Test6 starts:=====\n"); ListNode* pNode1 = CreateListNode(1); ListNode* pNode2 = CreateListNode(2); ListNode* pNode3 = CreateListNode(3); ListNode* pNode4 = CreateListNode(4); ListNode* pNode5 = CreateListNode(5); ConnectListNodes(pNode1, pNode2); ConnectListNodes(pNode2, pNode3); ConnectListNodes(pNode3, pNode4); ConnectListNodes(pNode4, pNode5); printf("expected result: nullptr.\n"); ListNode* pNode = FindKthToTail(pNode1, 0); PrintListNode(pNode); DestroyList(pNode1); } int main(int argc, char* argv[]) { Test1(); Test2(); Test3(); Test4(); Test5(); Test6(); return 0; }
// 面试题52:两个链表的第一个公共结点
// 题目:输入两个链表,找出它们的第一个公共结点。
#include <cstdio>
#include "..\Utilities\List.h"
unsigned int GetListLength(ListNode* pHead);
ListNode* FindFirstCommonNode(ListNode *pHead1, ListNode *pHead2)
{
// 得到两个链表的长度
unsigned int nLength1 = GetListLength(pHead1);
unsigned int nLength2 = GetListLength(pHead2);
int nLengthDif = nLength1 - nLength2;
ListNode* pListHeadLong = pHead1;
ListNode* pListHeadShort = pHead2;
if(nLength2 > nLength1)
{
pListHeadLong = pHead2;
pListHeadShort = pHead1;
nLengthDif = nLength2 - nLength1;
}
// 先在长链表上走几步,再同时在两个链表上遍历
for(int i = 0; i < nLengthDif; ++i)
pListHeadLong = pListHeadLong->m_pNext;
while((pListHeadLong != nullptr) &&
(pListHeadShort != nullptr) &&
(pListHeadLong != pListHeadShort))
{
pListHeadLong = pListHeadLong->m_pNext;
pListHeadShort = pListHeadShort->m_pNext;
}
// 得到第一个公共结点
ListNode* pFisrtCommonNode = pListHeadLong;
return pFisrtCommonNode;
}
unsigned int GetListLength(ListNode* pHead)
{
unsigned int nLength = 0;
ListNode* pNode = pHead;
while(pNode != nullptr)
{
++nLength;
pNode = pNode->m_pNext;
}
return nLength;
}
// ====================测试代码====================
void DestroyNode(ListNode* pNode);
void Test(char* testName, ListNode* pHead1, ListNode* pHead2, ListNode* pExpected)
{
if(testName != nullptr)
printf("%s begins: ", testName);
ListNode* pResult = FindFirstCommonNode(pHead1, pHead2);
if(pResult == pExpected)
printf("Passed.\n");
else
printf("Failed.\n");
}
// 第一个公共结点在链表中间
// 1 - 2 - 3 \
// 6 - 7
// 4 - 5 /
void Test1()
{
ListNode* pNode1 = CreateListNode(1);
ListNode* pNode2 = CreateListNode(2);
ListNode* pNode3 = CreateListNode(3);
ListNode* pNode4 = CreateListNode(4);
ListNode* pNode5 = CreateListNode(5);
ListNode* pNode6 = CreateListNode(6);
ListNode* pNode7 = CreateListNode(7);
ConnectListNodes(pNode1, pNode2);
ConnectListNodes(pNode2, pNode3);
ConnectListNodes(pNode3, pNode6);
ConnectListNodes(pNode4, pNode5);
ConnectListNodes(pNode5, pNode6);
ConnectListNodes(pNode6, pNode7);
Test("Test1", pNode1, pNode4, pNode6);
DestroyNode(pNode1);
DestroyNode(pNode2);
DestroyNode(pNode3);
DestroyNode(pNode4);
DestroyNode(pNode5);
DestroyNode(pNode6);
DestroyNode(pNode7);
}
// 没有公共结点
// 1 - 2 - 3 - 4
//
// 5 - 6 - 7
void Test2()
{
ListNode* pNode1 = CreateListNode(1);
ListNode* pNode2 = CreateListNode(2);
ListNode* pNode3 = CreateListNode(3);
ListNode* pNode4 = CreateListNode(4);
ListNode* pNode5 = CreateListNode(5);
ListNode* pNode6 = CreateListNode(6);
ListNode* pNode7 = CreateListNode(7);
ConnectListNodes(pNode1, pNode2);
ConnectListNodes(pNode2, pNode3);
ConnectListNodes(pNode3, pNode4);
ConnectListNodes(pNode5, pNode6);
ConnectListNodes(pNode6, pNode7);
Test("Test2", pNode1, pNode5, nullptr);
DestroyList(pNode1);
DestroyList(pNode5);
}
// 公共结点是最后一个结点
// 1 - 2 - 3 - 4 \
// 7
// 5 - 6 /
void Test3()
{
ListNode* pNode1 = CreateListNode(1);
ListNode* pNode2 = CreateListNode(2);
ListNode* pNode3 = CreateListNode(3);
ListNode* pNode4 = CreateListNode(4);
ListNode* pNode5 = CreateListNode(5);
ListNode* pNode6 = CreateListNode(6);
ListNode* pNode7 = CreateListNode(7);
ConnectListNodes(pNode1, pNode2);
ConnectListNodes(pNode2, pNode3);
ConnectListNodes(pNode3, pNode4);
ConnectListNodes(pNode4, pNode7);
ConnectListNodes(pNode5, pNode6);
ConnectListNodes(pNode6, pNode7);
Test("Test3", pNode1, pNode5, pNode7);
DestroyNode(pNode1);
DestroyNode(pNode2);
DestroyNode(pNode3);
DestroyNode(pNode4);
DestroyNode(pNode5);
DestroyNode(pNode6);
DestroyNode(pNode7);
}
// 公共结点是第一个结点
// 1 - 2 - 3 - 4 - 5
// 两个链表完全重合
void Test4()
{
ListNode* pNode1 = CreateListNode(1);
ListNode* pNode2 = CreateListNode(2);
ListNode* pNode3 = CreateListNode(3);
ListNode* pNode4 = CreateListNode(4);
ListNode* pNode5 = CreateListNode(5);
ConnectListNodes(pNode1, pNode2);
ConnectListNodes(pNode2, pNode3);
ConnectListNodes(pNode3, pNode4);
ConnectListNodes(pNode4, pNode5);
Test("Test4", pNode1, pNode1, pNode1);
DestroyList(pNode1);
}
// 输入的两个链表有一个空链表
void Test5()
{
ListNode* pNode1 = CreateListNode(1);
ListNode* pNode2 = CreateListNode(2);
ListNode* pNode3 = CreateListNode(3);
ListNode* pNode4 = CreateListNode(4);
ListNode* pNode5 = CreateListNode(5);
ConnectListNodes(pNode1, pNode2);
ConnectListNodes(pNode2, pNode3);
ConnectListNodes(pNode3, pNode4);
ConnectListNodes(pNode4, pNode5);
Test("Test5", nullptr, pNode1, nullptr);
DestroyList(pNode1);
}
// 输入的两个链表有一个空链表
void Test6()
{
Test("Test6", nullptr, nullptr, nullptr);
}
void DestroyNode(ListNode* pNode)
{
delete pNode;
pNode = nullptr;
}
int main(int argc, char* argv[])
{
Test1();
Test2();
Test3();
Test4();
Test5();
Test6();
return 0;
}
// 面试题51:数组中的逆序对
// 题目:在数组中的两个数字如果前面一个数字大于后面的数字,则这两个数字组
// 成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。
#include <cstdio>
int InversePairsCore(int* data, int* copy, int start, int end);
int InversePairs(int* data, int length)
{
if(data == nullptr || length < 0)
return 0;
int* copy = new int[length];
for(int i = 0; i < length; ++i)
copy[i] = data[i];
int count = InversePairsCore(data, copy, 0, length - 1);
delete[] copy;
return count;
}
int InversePairsCore(int* data, int* copy, int start, int end)
{
if(start == end)
{
copy[start] = data[start];
return 0;
}
int length = (end - start) / 2;
int left = InversePairsCore(copy, data, start, start + length);
int right = InversePairsCore(copy, data, start + length + 1, end);
// i初始化为前半段最后一个数字的下标
int i = start + length;
// j初始化为后半段最后一个数字的下标
int j = end;
int indexCopy = end;
int count = 0;
while(i >= start && j >= start + length + 1)
{
if(data[i] > data[j])
{
copy[indexCopy--] = data[i--];
count += j - start - length;
}
else
{
copy[indexCopy--] = data[j--];
}
}
for(; i >= start; --i)
copy[indexCopy--] = data[i];
for(; j >= start + length + 1; --j)
copy[indexCopy--] = data[j];
return left + right + count;
}
// ====================测试代码====================
void Test(char* testName, int* data, int length, int expected)
{
if(testName != nullptr)
printf("%s begins: ", testName);
if(InversePairs(data, length) == expected)
printf("Passed.\n");
else
printf("Failed.\n");
}
void Test1()
{
int data[] = { 1, 2, 3, 4, 7, 6, 5 };
int expected = 3;
Test("Test1", data, sizeof(data) / sizeof(int), expected);
}
// 递减排序数组
void Test2()
{
int data[] = { 6, 5, 4, 3, 2, 1 };
int expected = 15;
Test("Test2", data, sizeof(data) / sizeof(int), expected);
}
// 递增排序数组
void Test3()
{
int data[] = { 1, 2, 3, 4, 5, 6 };
int expected = 0;
Test("Test3", data, sizeof(data) / sizeof(int), expected);
}
// 数组中只有一个数字
void Test4()
{
int data[] = { 1 };
int expected = 0;
Test("Test4", data, sizeof(data) / sizeof(int), expected);
}
// 数组中只有两个数字,递增排序
void Test5()
{
int data[] = { 1, 2 };
int expected = 0;
Test("Test5", data, sizeof(data) / sizeof(int), expected);
}
// 数组中只有两个数字,递减排序
void Test6()
{
int data[] = { 2, 1 };
int expected = 1;
Test("Test6", data, sizeof(data) / sizeof(int), expected);
}
// 数组中有相等的数字
void Test7()
{
int data[] = { 1, 2, 1, 2, 1 };
int expected = 3;
Test("Test7", data, sizeof(data) / sizeof(int), expected);
}
void Test8()
{
int expected = 0;
Test("Test8", nullptr, 0, expected);
}
int main(int argc, char* argv[])
{
Test1();
Test2();
Test3();
Test4();
Test5();
Test6();
Test7();
Test8();
return 0;
}