由于之前看了牛客网的数据结构和算法的课程知道了左神,现在找到了这本书当作入门书做做吧,虽然书的题解都是java实现的,但好在用c++实现难度不大。
第二章 链表问题
第一题:环形单链表的约瑟夫问题
据说著名的犹太历史学家Josephus有过以下故事:在罗马人占领桥塔帕特后,39个犹太人与Josephus 及他的朋友躲到一个洞中,39个犹太人宁愿死也不要被敌人抓到,于是决定了一个自杀方式,41个人排成一个圆圈,由第一个人开始报数,报数到3的人就自杀,然后再有下一个人重新报1,报数到3的人再自杀。这样依次下去,直到剩下最后一个人时,那个人可以自由选择自己的命运。这就是著名的约瑟夫问题。现在请用单向环形链表描述该结构并呈现整个自杀过程。
输入:一个环形单向链表的头节点head 和报数的值m。
返回:最后生存下来的节点,且这个节点自己组成环形单向链表,其他节点都删掉。
之前已经反复说过,如果要删除一个节点,则要找到他之前的节点。首先遍历找到head之前的节点pre,然后按题意做下去即可,时间复杂度为O(n*m)。
struct ListNode {
int val;
ListNode *next;
ListNode(int x) : val(x), next(NULL) {}
};
ListNode* josephusKill(ListNode *head, int m) {
if (head == NULL || head->next == head || m < 1) {
return head;
}
ListNode* pre = head;
while (pre->next != head) {
pre = pre->next;
}
int count = 0;
while (head->next!=head) {
if (count != m-1) {
pre = head;
head = head->next;
++count;
}
else {
pre->next = head->next;
head = head->next;
count = 0;
}
}
return head;
}
题目二:判断一个链表是否为回文结构
回文用栈结构。
方法一:直接全放进栈中再进行出栈比对,额外空间复杂度为O(n);
方法二:对方法一进行了优化,虽然也是利用栈结构,但只压入一半的节点。
#include<stack>
using namespace std;
struct ListNode {
int val;
ListNode *next;
ListNode(int x) : val(x), next(NULL) {}
};
bool isPalindrome2(ListNode *head) {
//关键在如下两步找到右区间的头结点
ListNode* right = head->next, *cur = head;
while (cur->next != NULL || cur->next->next != NULL) {
right = right->next;
cur = cur->next->next;
}
stack<int> stack;
while (cur->next != NULL) {
stack.push(cur->val);
cur = cur->next;
}
while (!stack.empty()) {
if (head->val != stack.top()) {
return false;
}
head = head->next;
stack.pop();
}
return true;
}