链表

合并两个有序链表

合并两个有序链表

将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。

递归

思路:首先判断是否存在空链表,若存在返回另一个即可。其次取两个链表的最小值相比较,将较大的节点拼接在较小的节点之后,保留较小的值,将剩余节点按照同样方法凭借,不断修改next的值即可。


class Solution {
public:
ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) {
if(list1 == nullptr)
{
return list2;
}else if(list2 == nullptr)
{
return list1;
}else if(list1->val<list2->val){
list1->next=mergeTwoLists(list1->next,list2);
return list1;
}else {
list2->next=mergeTwoLists(list1,list2->next);
return list2;
}
}
};

迭代

思路:新建一条链表,设立哨兵节点,方便返回链表,每次取两条链表的最小值的节点,连接到新链表中,直到有链表为空,将剩余的存入新链表中,最后返回链表即可。


class Solution {
public:
ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) {
ListNode * temp=new ListNode(-1);
ListNode * pre =temp;
while(list1 !=nullptr &&list2 !=nullptr)
{
if(list1->val<list2->val)
{
pre->next=list1;
list1=list1->next;
}
else{
pre->next=list2;
list2=list2->next;
}
pre=pre->next;
}
pre->next=list1==nullptr ?list2:list1;
return temp->next;
}
};

删除排序链表中的重复元素

删除排序链表中的重复元素

给定一个已排序的链表的头 head ,删除所有重复的元素,使每个元素只出现一次 。返回 已排序的链表 。

思路:由于给定的链表是排好序的,因此重复的元素在链表中出现的位置是连续的,因此我们只需要对链表进行一次遍历,就可以删除重复的元素。

具体地,我们从指针 cur指向链表的头节点,随后开始对链表进行遍历。如果当前 cur 与 cur.next对应的元素相同,那么我们就将 cur.next从链表中移除;否则说明链表中已经不存在其它与 cur 对应的元素相同的节点,因此可以将 cur 指向 cur.next。

当遍历完整个链表之后,我们返回链表的头节点即可。

class Solution {
public:
ListNode* deleteDuplicates(ListNode* head) {
if(!head)
{
return head;
}
ListNode* cur=head;
while(cur->next)
{
if(cur->val==cur->next->val)
{
cur->next=cur->next->next;
}
else{
cur=cur->next;
}
}
return head;
}
};

环形链表

环形链表

给你一个链表的头节点 head ,判断链表中是否有环。

如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。注意:pos 不作为参数进行传递 。仅仅是为了标识链表的实际情况。

如果链表中存在环,则返回 true 。 否则,返回 false

快慢指针法

我们定义两个指针,一快一慢。慢指针每次只移动一步,而快指针每次移动两步。初始时,慢指针在位置 head,而快指针在位置 head.next。这样一来,如果在移动的过程中,快指针反过来追上慢指针,就说明该链表为环形链表。否则快指针将到达链表尾部,该链表不为环形链表。

class Solution {
public:
bool hasCycle(ListNode *head) {
if (head == nullptr || head->next == nullptr) {
return false;
}
ListNode *slow=head;
ListNode *fast=head->next;
while(slow!=fast)
{
if(fast==nullptr||fast->next==nullptr )
{
return false;
}
else{
slow=slow->next;
fast=fast->next->next;
}
}
return true;
}
};

哈希表法

我们可以使用哈希表来存储所有已经访问过的节点。每次我们到达一个节点,如果该节点已经存在于哈希表中,则说明该链表是环形链表,否则就将该节点加入哈希表中。重复这一过程,直到我们遍历完整个链表即可。

class Solution {
public:
bool hasCycle(ListNode *head) {
unordered_set<ListNode*> seen;
while (head != nullptr) {
if (seen.count(head)) {
return true;
}
seen.insert(head);
head = head->next;
}
return false;
}
};

两数之和

给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。

你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。

你可以按任意顺序返回答案。

穷举暴力

class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
int n = nums.size();
for (int i = 0; i < n; ++i) {
for (int j = i + 1; j < n; ++j) {
if (nums[i] + nums[j] == target) {
return {i, j};
}
}
}
return {};
}
};

哈希表

class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map<int,int> hashtable;
for(int i =0; i<nums.size();++i)
{
auto it =hashtable.find(target-nums[i]);
if(it!=hashtable.end()){
return {it->second,i};
}
hashtable[nums[i]]=i;
}
return {};
}
};