LeetCode算法题Day4

1、删除链表的倒数第N个结点

题目:给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。

解题:先遍历一下链表看有几个结点,然后再遍历一遍进行删除

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        auto dummy = new ListNode(-1);
        dummy->next=head;
        int k = 0;
        for(auto p=dummy->next;p;p=p->next)k++;
        // printf("%d",k);
        auto cur = dummy;
        for(int i=1;i<=k-n;i++)cur=cur->next;
        cur->next=cur->next->next;
        return dummy->next;
    }
};

2、有效的括号

题目:给定一个只包括 '('')''{''}''['']' 的字符串 s ,判断字符串是否有效。

有效字符串需满足:

  1. 左括号必须用相同类型的右括号闭合。
  2. 左括号必须以正确的顺序闭合。
  3. 每个右括号都有一个对应的相同类型的左括号。

解题:开一个栈来辅助匹配,当是 ( 或 [ 或 { 时入栈,否则(是 ) 或 ] 或 } )开始判断是否能匹配前一个字符,可以写多个分支来判断,或者观察ASCII码进行判断

 

class Solution {
public:
    bool isValid(string s) {
        stack<char> stk;
        for(int i=0;i<s.size();i++){
            if(s[i]=='('||s[i]=='['||s[i]=='{')stk.push(s[i]);
            else {
                if(stk.size()!=0&&abs(stk.top()-s[i])<=2)stk.pop();
                else return false;
            }
        }
        return stk.empty();
    }
};

3、合并两个有序链表

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

解题:新开一个链表,同时遍历两个升序链表,比较每次读到的结点,小的结点接到新链表的后面指针向后移,直至遍历完两个链表将新链表返回

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) {
        auto dummy = new ListNode(-1);//虚拟头结点
        auto tail = dummy;//添加结点时候使用
        while(list1&&list2){
            if(list1->val<list2->val){
                tail->next=list1;
                tail=tail->next;
                list1=list1->next;
            }else{
                tail->next=list2;
                tail=tail->next;
                list2=list2->next;
            }
        }
        if(list1)tail->next=list1;
        else if(list2)tail->next=list2;
        return dummy->next;
    }
};

4、括号生成

题目:数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。

解题:可以看成有2*n个位置,到某一个位置时填 '(' 还是 ')',此时有两个条件:当前位置之前的左括号小于n可以填左括号;当前位置前的左括号数>右括号数可以填右括号,递归填写

class Solution {
public:
    vector<string> res;
    vector<string> generateParenthesis(int n) {
        def(n,0,0,"");
        return res;
    }
    void def(int n,int l_cnt,int r_cnt,string s){
        if(s.size()==2*n)res.push_back(s);
        else{
            if(l_cnt<n)def(n,l_cnt+1,r_cnt,s+'(');
            if(r_cnt<n&&l_cnt>r_cnt)def(n,l_cnt,r_cnt+1,s+')');
        }
    }
};

5、合并K个升序列表

题目:给你一个链表数组,每个链表都已经按升序排列。

请你将所有链表合并到一个升序链表中,返回合并后的链表。

解题:最先想到的是每次遍历一遍所有链表的头找到一个最小的插入要返回的链表中,时间复杂度是k*n(粗略表示每个链表有n个结点),使用堆排序的思想优化一下,先把每个链表的头插入到堆中,然后利用堆的自动排序拿出最小的插入到要返回的链表中,然后将这个结点的下一个结点插入到堆中,重复这个动作,直至堆空,时间复杂度为n*logn

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    struct Cmp{
        bool operator() (ListNode* a,ListNode* b){
            return a->val > b->val;
        }
    };
    ListNode* mergeKLists(vector<ListNode*>& lists) {
        auto dummy = new ListNode(-1);
        auto tail = dummy;
        priority_queue<ListNode*,vector<ListNode*>,Cmp> heap;
        for(auto l:lists){
           if(l) heap.push(l);
        }
        while(heap.size()){
            auto t = heap.top();
            heap.pop();
            tail->next=t;
            tail=tail->next;
            if(t->next)heap.push(t->next);
        }
        return dummy->next;
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值