LeetCode hot-100 简单and中等难度,1-10.

1. 两数之和

难度简单8834

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

你可以假设每种输入只会对应一个答案。但是,数组中同一个元素不能使用两遍。

 

示例:

给定 nums = [2, 7, 11, 15], target = 9

因为 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [0, 1]
class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        for(int i=0;i<nums.size();i++){
            for(int j=i+1;j<nums.size();j++){
                if(nums[i]+nums[j]==target){
                    return {i,j};
                }
            }
        }
        return {};
    }
};

解法分析:

1、暴力法

双层遍历,nums[i]+nums[j]=target即可。

2、两遍哈希表/一遍哈希表

注意在两遍哈希时,有可能有重复数,因此判断:
if(m.find(target-nums[i]) != m.end() && m[target-nums[i]] != i)

在一遍哈希时,将map.put(nums[i],i)放在判断之后
if(m.find(target-nums[i]) != m.end())     return {m[target-nums[i]], i};        
m[nums[i]] = i;       //向map中添加元素

以上判断是因为在哈希表中存的是mp[nums[i]]=i;

2. 两数相加

难度中等4714

给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。

如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。

您可以假设除了数字 0 之外,这两个数都不会以 0 开头。

示例:

输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
输出:7 -> 0 -> 8
原因:342 + 465 = 807
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
        //有一个哑结点方便。
        ListNode* l3= new ListNode(-1);
        ListNode* ans=l3;
        int carry=0;
        int sum=0;
        //接下来就是普通的相加+进位。
        while(l1||l2){
            sum=carry;
            if(l1){
                sum+=l1->val;
                l1=l1->next;
            }
            if(l2){
                sum+=l2->val;
                l2=l2->next;
            }
            carry=sum/10;
            sum=sum%10;
            l3->next= new ListNode(sum);
            l3=l3->next;
        }
        if(carry!=0) l3->next= new ListNode(carry);
        return ans->next;
    }
};
拓展
如果链表中的数字不是按逆序存储的呢?例如:
(3→4→2)+(4→6→5)=8→0→7

原题:
输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
输出:7 -> 0 -> 8
原因:342 + 465 = 807

所以加法要从最低位开始,拓展的解法应该是用栈吧...?

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

难度中等4113

给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。

示例 1:

输入: "abcabcbb"
输出: 3 
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。

示例 2:

输入: "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。

示例 3:

输入: "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
     请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。

滑动窗口典型题目,滑动窗口需要再看典型框架解法。


class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        unordered_map<char,int> windows;
        int left=0,right=0;int ans=0;
        while(right<s.size()){
            char c=s[right];
            windows[c]++;
            right++;
            while(windows[c]>1){
                char c=s[left];
                left++;
                windows[c]--;
            }
            ans=max(ans,right-left);
        }
        return ans;
    }
};

4困难题跳过

5. 最长回文子串

难度中等2529

给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。

示例 1:

输入: "babad"
输出: "bab"
注意: "aba" 也是一个有效答案。

示例 2:

输入: "cbbd"
输出: "bb"

典型动态规划,解法都应该背过了,面试记住股票那两个题~

class Solution {
public:
    string longestPalindrome(string s) {
        //经典动态规划
        //最长回文子串
        //dp[i][j]表示i到j之间的是不是回文子串!
        // int dp[1010][1010];
        int len=s.length();
         vector<vector<int>> dp (len,vector<int>(len));
        //1表示是,0表示不是
        int ans=1;int start=0;
        //边界
        for(int i=0;i<len;i++){
            dp[i][i]=1;
            if(i!=len-1){
                if(s[i]==s[i+1]){
                    dp[i][i+1]=1;ans=2;start=i;
                }
            }
        }
        //长度,左指针!
        for(int l=3;l<=len;l++){
            for(int i=0;i+l-1<len;i++){
                int j=i+l-1;
                if(s[i]==s[j]) dp[i][j]=dp[i+1][j-1];
                else dp[i][j]=0;
                if(dp[i][j]){
                    ans=l;start=i;
                }
            }
        }
        return s.substr(start,ans);

    }
};
注意这种解法是斜着填表的典型!

优化解法:中心扩散法

除了枚举字符串的左右边界以外,比较容易想到的是枚举可能出现的回文子串的“中心位置”,从“中心位置”尝试尽可能扩散出去,得到一个回文串。
因此中心扩散法的思路是:遍历每一个索引,以这个索引为中心,利用“回文串”中心对称的特点,往两边扩散,看最多能扩散多远。
枚举“中心位置”时间复杂度为 O(N)O,从“中心位置”扩散得到“回文子串”的时间复杂度为 O(N),因此时间复杂度可以降到O(N^2)。

当然奇偶代码有所不同..
class Solution {

private:

    string centerSpread(string s, int left, int right) {
        // left = right 的时候,此时回文中心是一个空隙,向两边扩散得到的回文子串的长度是奇数
        // right = left + 1 的时候,此时回文中心是一个字符,向两边扩散得到的回文子串的长度是偶数
        int size = s.size();
        int i = left;
        int j = right;
        while (i >= 0 && j < size) {
            if (s[i] == s[j]) {
                i--;
                j++;
            } else {
                break;
            }
        }
        // 这里要小心,跳出 while 循环时,恰好满足 s.charAt(i) != s.charAt(j),因此不能取 i,不能取 j
        return s.substr(i + 1, j - i - 1);
    }

public:


    string longestPalindrome(string s) {
        // 特判
        int size = s.size();
        if (size < 2) {
            return s;
        }

        int maxLen = 1;
        string res = s.substr(0, 1);

        // 中心位置枚举到 len - 2 即可
        for (int i = 0; i < size - 1; i++) {
            string oddStr = centerSpread(s, i, i);
            string evenStr = centerSpread(s, i, i + 1);
            string maxLenStr = oddStr.size() > evenStr.size() ? oddStr : evenStr;
            if (maxLenStr.length() > maxLen) {
                maxLen = maxLenStr.size();
                res = maxLenStr;
            }
        }
        return res;
    }
};

作者:liweiwei1419
链接:https://leetcode-cn.com/problems/longest-palindromic-substring/solution/zhong-xin-kuo-san-dong-tai-gui-hua-by-liweiwei1419/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

7. 盛最多水的容器

难度中等1707

给你 n 个非负整数 a1,a2,...,an,每个数代表坐标中的一个点 (iai) 。在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (iai) 和 (i, 0)。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。

说明:你不能倾斜容器,且 n 的值至少为 2。

 

图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。

 

示例:

输入:[1,8,6,2,5,4,8,3,7]
输出:49

典型双指针 ,难度不大

class Solution {
public:
    int maxArea(vector<int>& height) {
        int x=0,y=height.size()-1;
        int ans=0;
        while(x!=y){
            int tmp=min(height[x],height[y])*(y-x);
            if(tmp>ans) ans=tmp;
            if(min(height[x],height[y])==height[x]){
                x++;
            }else y--;
        }
        return ans;

    }
};

 

就是看图说话呗,长方形由nums[I] nums[j]组成~

最优做法就是双指针,初始指向数组左右两端,然后根据情况挪动。移动 数字较小的那个指针。

15. 三数之和

难度中等2458

给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有满足条件且不重复的三元组。

注意:答案中不可以包含重复的三元组。

 

示例:

给定数组 nums = [-1, 0, 1, 2, -1, -4],

满足要求的三元组集合为:
[
  [-1, 0, 1],
  [-1, -1, 2]
]

 n数之和加去重操作

class Solution {
public:
    vector<vector<int>> twoSum(vector<int> nums,int target,int start){
        int l=start;int r=nums.size()-1;
        vector<vector<int>> ans;
        while(l<r){
            int sum=nums[l]+nums[r];
            int left=nums[l];
            int right=nums[r];
            if(sum>target){
                r--;
                while(l<r&&nums[r]==right) r--;
            }else if(sum<target){
                l++;
                while(l<r&&nums[l]==left) l++;
            }else{
                ans.push_back({left,right});
                while(l<r&&nums[r]==right) r--;
                while(l<r&&nums[l]==left) l++;
            }
        }
        return ans;
    }
    vector<vector<int>> threeSum(vector<int>& nums) {
        vector<vector<int>> ans;
        sort(nums.begin(),nums.end());
        for(int i=0;i<nums.size();i++){
            vector<vector<int>> tuples=twoSum(nums,0-nums[i],i+1);
            for(vector<int>& tuple:tuples){
                tuple.push_back(nums[i]);
                ans.push_back(tuple);
            }
            while(i<nums.size()-1&&nums[i]==nums[i+1]) i++;
        }
        return ans;
    }
};
就是枚举第一个数,然后再找两数之和。
需要注意的是去重操作。

 

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

难度中等926

给定一个链表,删除链表的倒数第 个节点,并且返回链表的头结点。

示例:

给定一个链表: 1->2->3->4->5, 和 n = 2.

当删除了倒数第二个节点后,链表变为 1->2->3->5.

说明:

给定的 n 保证是有效的。

进阶:

你能尝试使用一趟扫描实现吗?

//解法1,两次遍历,删除列表开头的第L-n+1个结点。

注意添加一个哑结点作为辅助。

ListNode* removeNthFromEnd(ListNode* head, int n) {
    ListNode* ans=new ListNode(0);
        ans->next=head;
        ListNode* first=head;
        int cnt=0;
        while(first!=NULL){
            first=first->next;cnt++;
        }
        cnt-=n;
        first=ans;
        while(cnt>0){
            first=first->next;cnt--;
        }
        first->next=first->next->next;
        return ans->next;
}

//解法2:一次遍历。使用两个指针。

第一个指针从列表的开头向前移动 n+1步,而第二个指针将从列表的开头出发。现在,这两个指针被 n个结点分开。我们通过同时移动两个指针向前来保持这个恒定的间隔,直到第一个指针到达最后一个结点。此时第二个指针将指向从最后一个结点数起的第 n个结点。
ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode* ans=new ListNode(0);
        ans->next=head;
        ListNode* first=ans;
        ListNode* second=ans;
        for(int i=0;i<=n;i++){
            first=first->next;
        }
        //second->0->1...   first->2
        while(first!=NULL){
            first=first->next;
            second=second->next;
        }
        second->next=second->next->next;
        return ans->next;
    }



 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值