链表的实现
struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
最基本的实现链表的左右孩子指针,以及构造函数
链表的使用
我在做题中的习惯,是首先申请一个head节点,记得要申请空间TreeNode* head = new TreeNode()
当然通过《程序员面试宝典》中提到,指针是可以定义的时候不申请空间,让其没有指向,但是引用定义时要有确定的网址。这里的head是为了我们返回结果链表时的首地址,返回head->next
除了head,就是申请TreeNode* p;
指针p用来遍历我们的结果链表,或者添加节点,类似于游标
如果是对于两个链表做运算,那么就是一个while(l1!=nullptr && l2!=nullptr)
,while运行结束,l1和l2至少有一个是遍历结束了,if(l1==nullptr){while (l2……)}
if(l2==nullptr){while (l1……)}
Leetcode 206 反转链表
反转一个单链表。
示例:
输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL
class Solution {
public:
ListNode* reverseList(ListNode* head) {
stack<int> stack_list;
ListNode* p ;
ListNode* reverse = new ListNode();
ListNode* cur = reverse;
for(p = head; p!=nullptr; p = p->next){
stack_list.push(p->val);
}
while(!stack_list.empty()){
int value = stack_list.top();
ListNode* node = new ListNode(value);
reverse->next = node;
reverse = reverse->next;
stack_list.pop();
}
return cur->next;
}
};
最简单的想法就是用一个栈遍历,再依次取出,构造结果链表。
这道题虽然简单,但是面试可能会问到,需要快速的写出答案,并且结果应该尽量简洁吧。
Leetcode官网给出的一种方法,可以节省空间的消耗。
class Solution {
public:
ListNode* reverseList(ListNode* head) {
ListNode* prev = nullptr;
ListNode* curr = head;
while (curr) {
ListNode* next = curr->next;
curr->next = prev;
prev = curr;
curr = next;
}
return prev;
}
};
一共是三个指针在活动要分清。首先翻转是从我们获得的链表到链尾遍历,改变它的prev指针指向自己的上一个被遍历到的节点,也就是逆序,curr表示当前正在操作的节点。next指针保存当前节点的next指针。因为当前next指针要指向逆序prev,所以在改变next指针之前,先把当前的next保存下来,为了遍历原链表的下一个节点。
Leetcode 141 环形链表
给定一个链表,判断链表中是否有环。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。
如果链表中存在环,则返回 true 。 否则,返回 false 。
快慢指针法:
class Solution {
public:
bool hasCycle(ListNode *head) {
if(head==NULL){
return false;
}
ListNode *fast = head;
ListNode *slow = head;
while(fast->next!=NULL && slow->next != NULL && fast->next->next!=NULL){
cout << "falst" << fast->val << "slow" << slow->val;
fast = fast->next->next;
slow = slow->next;
if(fast==slow){
return true;
}
}
return false;
}
};
Leetcode 287 寻找重复数
将链表的遍历顺序想象成一个跑到,如果快指针fast每次走两步,慢指针slow每次走一步,如果存在环,fast一定“扣圈”慢指针,在某一个位置相遇,这里判定的条件是地址,所以不用担心相同大小数字的干扰。
给定一个包含 n + 1 个整数的数组 nums ,其数字都在 1 到 n 之间(包括 1 和 n),可知至少存在一个重复的整数。
假设 nums 只有 一个重复的整数 ,找出 这个重复的数 。
解答:
这道题用哈希表非常容易可以找到答案。
官方同时也用到了环形链表的解法
class Solution {
public:
int findDuplicate(vector<int>& nums) {
int slow = 0, fast = 0;
do {
slow = nums[slow];
fast = nums[nums[fast]];
} while (slow != fast);
slow = 0;
while (slow != fast) {
slow = nums[slow];
fast = nums[fast];
}
return slow;
}
};
链表的建立是通过节点的值(数组的值,例如7),去连接索引为7的数组的值,nums[7]。因为存在重复数,一定会有环形链表,,通过使用快慢指针,找到环形的入口,也就是重复的值。但这里一直有个疑惑,如果出现nums[0] = 1, nums[1] = 0,两个指针只会在这两个数里面转,如何保证只存在由重复数组成的环,没怎么想明白。