算法-九阳天书

1. 两数之和

给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
你可以按任意顺序返回答案。
输入:nums = [2,7,11,15], target = 9
输出:[0,1] 解释:因为 nums[0] + nums[1] == 9,返回 [0, 1]。

解决方法:

vector<int> twoSum(vector<int>& nums, int target) {
        int n = nums.size();
        unordered_map<int, int> mp;
        mp[nums[0]] = -1;
        for(int i=1;i<n;i++){
            if(mp[target-nums[i]]==false){
                mp[nums[i]] = i;
            }else{
                if(mp[target-nums[i]]==-1){
                    return {0, i};
                }
                return {mp[target-nums[i]],i};
            }
        }
        return {};
    }

2. 两数相加

给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。
请你将两个数相加,并以相同形式返回一个表示和的链表。
你可以假设除了数字 0 之外,这两个数都不会以 0 开头。

在这里插入图片描述
输入:l1 = [2,4,3], l2 = [5,6,4] 输出:[7,0,8] 解释:342 + 465 = 807.

解决方法:
顺序的比较容易,加一个flag判断进位,不断生成一条链表,最后也要判断flag

class Solution {
public:
    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
        ListNode* p = l1;
        ListNode* q = l2;
        ListNode* t = new ListNode();
        ListNode* r = t;
        int flag = 0;
        while(p && q){
            int x = (p->val + q->val + flag) % 10;
            flag = (p->val + q->val + flag) / 10;
            r->next = new ListNode(x);
            r = r -> next;
            p = p->next;
            q = q->next;
        }
        while(p){
            int x = (p->val + flag) % 10;
            flag = (p->val + flag) / 10;
            r->next = new ListNode(x);
            r = r -> next;
            p = p->next;
        }
        while(q){
            int x = (q->val + flag) % 10;
            flag = (q->val + flag) / 10;
            r->next = new ListNode(x);
            r = r -> next;
            q = q->next;
        }
        if(flag){
            r->next = new ListNode(1);
        }
        return t->next;
    }
};

3. 无重复字符的最长子串

给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。
输入: s = “abcabcbb” 输出: 3 解释: 因为无重复字符的最长子串是 “abc”,所以其长度为 3。
输入: s = “bbbbb” 输出: 1 解释: 因为无重复字符的最长子串是 “b”,所以其长度为 1。

解题1:
滑动窗口,使用一个unordered_map来作为滑动窗口,每次无重复fast前进,重复了slow往前走到重复的位置,再+1

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        int n = s.size();
        int slow = 0, fast = 0;
        int res = 0;
        unordered_map<char,bool> mp;
        for(fast=0;fast<n;fast++){
            if(!mp[s[fast]]){
                mp[s[fast]] = true;
                res = max(res, fast-slow+1);
            }else{
                 while(s[slow]!=s[fast]){
                    mp[s[slow]] =false;
                    slow++;
                }
                slow++;
            }
           
        }
        return res;
    }
};

5. 最长回文子串

给你一个字符串 s,找到 s 中最长的回文子串。
如果字符串的反序与原始字符串相同,则该字符串称为回文字符串。
示例 1:
输入:s = “babad” 输出:“bab”
解释:“aba” 同样是符合题意的答案。
示例 2:
输入:s = “cbbd” 输出:“bb”

1 <= s.length <= 1000
s 仅由数字和英文字母组成

解题1:
双指针,每个字符的左右间隙都看作一个回文的中心点,每个字符也是,就有2倍n大小的回文中心点,从中心点往两边扩散,对比是否相同,记录最长的

string longestPalindrome(string s) {
        int n = s.size();
        int res = 1;
        int begin = 0;
        for(int i=0;i<n*2;i++){
            int a = i/2;
            int b = i/2 + i%2;
            while(a>=0 && b<n && s[a]==s[b]){
                if(b-a+1>res){
                    begin = a;
                    res = b-a+1;
                }
                a--;
                b++;
            }
        }
        return s.substr(begin, res);
    }

解题2:
动态规划,dp[i][j]表示字符串i到j是否是回文串,以L从2开始往上计算

string longestPalindrome(string s){
        int n = s.size();
        vector<vector<int>> dp(n, vector<int>(n,false));
        for(int i=0;i<n;i++)dp[i][i] = true;
        int begin = 0;
        int res = 1;
        for(int L=2;L<=n;L++){
            for(int i=0;i<n;i++){
                int j = i + L - 1;
                if(j>=n)break;
                if(s[i]!=s[j])dp[i][j] = false;
                else{
                    if(j-i+1<3)dp[i][j] = true; 
                    else dp[i][j] = dp[i+1][j-1];
                }
                if(dp[i][j] && (j-i+1)>res){
                    begin = i;
                    res = j-i+1;
                }                
            }
        }
        return s.substr(begin, res);
    }

6. N 字形变换

将一个给定字符串 s 根据给定的行数 numRows ,以从上往下、从左到右进行 Z 字形排列。
比如输入字符串为 “PAYPALISHIRING” 行数为 3 时,排列如下:
在这里插入图片描述之后,你的输出需要从左往右逐行读取,产生出一个新的字符串,比如:“PAHNAPLSIIGYIR”。

解题:
看成线性的,设置一个flag和index,每次index=0或者index=numRows-1时,flag取反,加到index,这样index就在一个范围里折返,使用一个vector记录每行的字符,最后读取

class Solution {
public:
    string convert(string s, int numRows) {
        int n = s.size();
        if(numRows==1)return s;
        vector<string> ans(numRows);
        int flag = 1;
        int index = 0;
        for(int i=0;i<n;i++){
            ans[index].push_back(s[i]);
            index += flag;
            if(index==numRows-1 || index==0)flag = -flag;
        }
        string res;
        for(auto str : ans)res+=str;
        return res;
    }
};

19.删除链表的倒数第 N 个结点

给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。
在这里插入图片描述
输入:head = [1,2,3,4,5], n = 2 输出:[1,2,3,5]

解题思路:
双指针一遍遍历,或者遍历两遍第一次查数量第二次计算,或者使用一个栈存储

class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode* h = new ListNode();
        h->next = head;

        ListNode* p = head;
        for(int i=0;i<n;i++)p = p->next;
        ListNode* q = h;
        while(p){
            p = p->next;
            q = q->next;
        }
        p = q->next;
        q->next = q->next->next;
        delete(p);
        return h->next;
    }
};

20.有效的括号

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

有效字符串需满足:

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

示例 1:输入:s = “()” 输出:true
示例 2:输入:s = “()[]{}” 输出:true
示例 3:输入:s = “(]” 输出:false

解题思路:
使用一个栈来存储,遍历字符串,当是左边的3种括号时入栈,当是右边3种括号需要判断,栈为空或者栈顶不为对应的左括号返回false,都正确就出栈一个,最后判断栈是否为空

class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode* h = new ListNode();
        h->next = head;

        ListNode* p = head;
        for(int i=0;i<n;i++)p = p->next;
        ListNode* q = h;
        while(p){
            p = p->next;
            q = q->next;
        }
        p = q->next;
        q->next = q->next->next;
        delete(p);
        return h->next;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值