1、链表中倒数第k个节点
题目:输入一个链表,输出该链表中倒数第k个节点。为了符合大多数人的习惯,本题从1开始计数,即链表的尾节点是倒数第1个节点。例如,一个链表有6个节点,从头节点开始,它们的值依次是1、2、3、4、5、6。这个链表的倒数第3个节点是值为4的节点。
ListNode* FindKthToTail(ListNode* pListHead, unsigned int k)
{
ListNode *pAhead = pListHead;
ListNode *pBehind = nullptr;
for(unsigned int i = 0; i < k-1; i++)
{
pAhead = pAhead->m_pNext;
}
pBehind = pListHead;
while(pAhead->m_pNext != nullptr)
{
pAhead = pAhead->m_pNext;
pBehind = pBehind->m_pNext;
}
return pBehind;
}
2、链表中环的入口节点
题目:如果一个链表中包含环,如何找出环的入口节点?
ListNode* MeetingNode(ListNode* pHead)
{
if(pHead == nullptr)
return nullptr;
ListNode* pSlow = pHead->m_pNext;
if(pSlow == nullptr)
return nullptr;
ListNode* pFast = pSlow->m_pNext;
while(pFast != nullptr && pSlow != nullptr)
{
if(pFast == pSlow)
return pFast;
pSlow = pSlow->m_pNext;
pFast = pFast->m_pNext;
if(pFast != nullptr)
pFast = pFast->m_pNext;
}
return nullptr;
}
ListNode* EntryNodeOfLoop(ListNode* pHead)
{
ListNode* meetingNode = MeetingNode(pHead);
if(meetingNode == nullptr)
return nullptr;
int nodesInLoop = 1;
ListNode* pNode1 = meetingNode;
while(pNode1->m_pNext != meetingNode)
{
pNode1 = pNode1->m_pNext;
++nodesInLoop;
}
pNode1 = pHead;
for(int i = 0; i < nodesInLoop; ++i)
pNode1 = pNode1->m_pNext;
ListNode* pNode2 = pHead;
while(pNode1 != pNode2)
{
pNode1 = pNode1->m_pNext;
pNode2 = pNode2->m_pNext;
}
return pNode1;
}
3、反转链表
题目:定义一个函数,输入一个链表的头节点,反转该链表并输出反转后链表的头节点。
ListNode* ReverseList(ListNode* pHead)
{
ListNode* pReversedHead = nullptr;
ListNode* pNode = pHead;
ListNode* pPrev = nullptr;
while(pNode != nullptr)
{
ListNode* pNext = pNode->m_pNext;
if(pNext == nullptr)
pReversedHead = pNode;
pNode->m_pNext = pPrev;
pPrev = pNode;
pNode = pNext;
}
return pReversedHead;
}
4、合并两个排序的链表
题目:输入两个递增排序的链表,合并这两个链表并使新链表中的节点仍然是递增排序的。
ListNode* Merge(ListNode* pHead1, ListNode* pHead2)
{
if(pHead1 == nullptr)
return pHead2;
else if(pHead2 == nullptr)
return pHead1;
ListNode* pMergedHead = nullptr;
if(pHead1->m_nValue < pHead2->m_nValue)
{
pMergedHead = pHead1;
pMergedHead->m_pNext = Merge(pHead1->m_pNext, pHead2);
}
else
{
pMergedHead = pHead2;
pMergedHead->m_pNext = Merge(pHead1, pHead2->m_pNext);
}
return pMergedHead;
}
struct ListNode* mergeTwoLists(struct ListNode* l1, struct ListNode* l2)
{
//加个链表头
struct ListNode head;
struct ListNode *pre = &head;
while (l1 && l2) {
if (l1->val <= l2->val) {
pre->next = l1;
l1 = l1->next;
} else {
pre->next = l2;
l2 = l2->next;
}
pre = pre->next;
}
//将剩下元素直接接在最后面
pre->next = (NULL == l1 ? l2 : l1);
return head.next;
}
5、树的子结构
题目:输入两棵二叉树A和B,判断B是不是A的子结构。
bool HasSubtree(BinaryTreeNode* pRoot1, BinaryTreeNode* pRoot2)
{
bool result = false;
if(pRoot1 != nullptr && pRoot2 != nullptr)
{
if(Equal(pRoot1->m_dbValue, pRoot2->m_dbValue))
result = DoesTree1HaveTree2(pRoot1, pRoot2);
if(!result)
result = HasSubtree(pRoot1->m_pLeft, pRoot2);
if(!result)
result = HasSubtree(pRoot1->m_pRight, pRoot2);
}
return result;
}
bool DoesTree1HaveTree2(BinaryTreeNode* pRoot1, BinaryTreeNode* pRoot2)
{
if(pRoot2 == nullptr)
return true;
if(pRoot1 == nullptr)
return false;
if(!Equal(pRoot1->m_dbValue, pRoot2->m_dbValue))
return false;
return DoseTree1HaveTree2(pRoot1->m_pLeft, pRoot2->m_pLeft) && DoseTree1HaveTree2(pRoot1->m_pRight, pRoot2->m_pRight);
}
bool Equal(double num1, double num2)
{
if((num1 - num2 > -0.0000001) && (num1 - num2 < 0.0000001))
return true;
else
return false;
}
6、判断单链表中是否存在环
bool IsExitsLoop(List *head)
{
List *slow = head, *fast = head;
while(fast && fast->next)
{
slow = slow->next;
fast = fast->next->next;
if(slow == fast) break;
}
return !(fast == NULL || fast->next == NULL);
}
7、回文链表
编写一个函数,检查输入的链表是否是回文的
思路:利用双指针找到链表的中间位置,然后将后半段反转,将后半段依次与前半段比较。
bool isPalindrome(struct ListNode* head){
struct ListNode* slow = head;
struct ListNode* fast = head;
struct ListNode* p = head;
while((fast!=NULL) &&(fast->next!=NULL))
{
slow = slow->next;
fast = fast->next->next;
}
struct ListNode *cur = slow;
struct ListNode *pre = NULL;
//将链表的后半段反转
while(cur!=NULL){
//保存下一个的值
struct ListNode* temp = cur->next;
//重新连接当前节点
cur->next = pre;
//更新pre
pre = cur;
//cur指向下一个
cur = temp;
}
// 将后半段反转的链表与前半段依次比较
while(pre&&head){
if(pre->val!=head->val)
return false;
pre=pre->next;head=head->next;
}
return true;
}
8、移除重复节点
编写代码,移除未排序链表中的重复节点。保留最开始出现的节点。
思路1:定义两个指针current和p来逐个遍历链表,current元素依次和p比较,直到p为NULL,current向后移动一个。
思路2:利用标记数组,标记当前值是否出现过。
方法1:
struct ListNode* removeDuplicateNodes(struct ListNode* head){
//判断是否需要遍历
if (head == NULL) return NULL;
struct ListNode* current = head;
//双指针逐个比较
while (current) {
struct ListNode* p = current;
while(p->next) {
if (p->next->val == current->val) {
p->next = p->next->next;
} else {
p = p->next;
}
}
current = current->next;
}
return head;
}
方法2:
struct ListNode* removeDuplicateNodes(struct ListNode* head){
//判断是否需要遍历
if(head==NULL || head->next==NULL)
return head;
//利用val的值在0~20000之间,标记是否出现过
int index[20001] = {0};
index[head->val] = 1;
struct ListNode *pre = head, *q = head->next;
while(q)
{
//当前val未出现过,保存当前val,修改pre和p指针
if(index[q->val]==0)
{
index[q->val] = 1;
pre = q;
q = q->next;
}
//当前值已经出现过了,删除当前节点
else
{
pre->next = q->next;
q = pre->next;
}
}
return head;
}
9、原地移除元素
一个(慢)num指针为数组本身进行复写,一个(快) p指针不断移动并判断是否等于val的值。一旦快指针所指向的值不等于val,则进行复写,将快指针所指向的值复写慢指针所指向的值,且计数器加一。(注意顺序:先*nums=p[i], 后nums++; 因为慢指针的最后一项总是待复写的位置,所以若快指针所指向的值不等于val时,先将快指针的值复写慢指针的值,将慢指针往后挪一位)
int removeElement(int* nums, int numsSize, int val){
int count=0;
int *p=nums;
for(int i=0;i<numsSize;i++){
if(p[i]!=val){
*nums=p[i];
nums++;
count++;
}
}
return count;
}
10、寻找数组的中心索引
中心索引:数组中心索引的左侧所有元素相加的和等于右侧所有元素相加的和。
方法一:
int pivotIndex(int* nums, int numsSize){
if (numsSize < 3)
{
return -1;
}
int sum = 0,right = 0,left = 0;
for(int i = 0;i <numsSize;i++)
{
sum+=nums[i];
}
for(int i = 0;i < numsSize;i++)
{
//计算右边的和
right = sum-nums[i]-left;
//左右相等则返回
if(left == right)
return i;
//左边求和
left += nums[i];
}
return -1;
}
方法二:
/*
* 1. 从位置0开始右移寻找,先计算left和right,然后每右移一位判断是否符合
*/
int pivotIndex(int* nums, int numsSize)
{
if (numsSize < 3) {
return -1;
}
int left = 0;
int right = 0;
for (int i = 1; i < numsSize; ++i) {
right += nums[i];
}
int pos = 0;
while (left != right) {
if (pos + 1 == numsSize) {
return -1;
}
left += nums[pos];
right -= nums[pos + 1];
pos++;
}
return pos;
}