LeetCode 算法系列:第 16 ~ 20 题

目录
16. 最接近的三数之和
17. 电话号码的字母组合
18. 四数之和
19. 删除链表的倒数第N个节点
20. 有效的括号

16. 最接近的三数之和

题目描述

给定一个包括 n 个整数的数组 nums 和 一个目标值 target。找出 nums 中的三个整数,使得它们的和与 target最接近。返回这三个数的和。假定每组输入只存在唯一答案。

示例:

输入:nums = [-1,2,1,-4], target = 1
输出:2
解释:与 target 最接近的和是 2 (-1 + 2 +1 = 2) 。

提示:

3 <= nums.length <= 10^3
-10^3 <= nums[i] <= 10^3
-10^4 <= target <=10^4

思路

排序 + 双指针
本题目因为要计算三个数,如果靠暴力枚举的话时间复杂度会到 O(n^3)需要降低时间复杂度 首先进行数组排序,时间复杂度
O(nlogn) 在数组 nums 中,进行遍历,每遍历一个值利用其下标i,形成一个固定值 nums[i] 再使用前指针指向 start
= i + 1 处,后指针指向 end = nums.length - 1 处,也就是结尾处 根据 sum = nums[i] + nums[start] + nums[end] 的结果,判断 sum 与目标 target 的距离,如果更近则更新结果 ans 同时判断
sum 与 target 的大小关系,因为数组有序,如果 sum > target 则 end–1, 如果 sum < target 则
start+1,如果 sum == target 则说明距离为 0 直接返回结果 整个遍历过程,固定值为 n 次,双指针为 n
次,时间复杂度为 O(n^2) 总时间复杂度:O(nlogn) + O(n^2) = O(n^2)

c++代码

class Solution {
public:
    int threeSumClosest(vector<int>& nums, int target) {
        int ans = 1000000000;
        sort(nums.begin(),nums.end());
        int n = nums.size();
        for(int i =0;i<nums.size();i++)
        {
            //if(i&&nums[i]==nums[i-1])continue;
            for(int j =i+1,k=nums.size()-1;j<k;)
            {
                //if(j>i+1&&nums[j]==nums[j-1])
                  //  continue;
                int sum = nums[i]+nums[j]+nums[k];
                if(sum==target)
                    return sum;
                if(abs(sum-target)<abs(ans-target))
                {
                    ans = sum;
                }
                if(sum>target)k--;
                if(sum<target)j++;
            }    
        }
        return ans;
    }
};

python 代码

class Solution(object):
    def threeSumClosest(self, nums, target):
        ans = 1e4
        nums.sort()
        n = len(nums)
        for i in range(n):
            if i != 0 and nums[i] == nums[i - 1]:
                continue
            j = i + 1
            k = n - 1
            while j < k:
                num = nums[i] + nums[j] + nums[k]
                if num == target:
                    return num
                if abs(num - target) < abs(ans - target):
                    ans = num
                if num > target:
                    k -= 1
                if num < target:
                    j += 1
        return ans
        """
        :type nums: List[int]
        :type target: int
        :rtype: int
        """

17. 电话号码的字母组合

题目描述

给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。 给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。
在这里插入图片描述

示例:

输入:“23”
输出:[“ad”, “ae”, “af”, “bd”, “be”, “bf”, “cd”, “ce”, “cf”].

思路

递归
可以通过手工或者循环的方式预处理每个数字可以代表哪些字母。 通过递归尝试拼接一个新字母。
递归到目标长度,将当前字母串加入到答案中。 注意,有可能数字串是空串,需要特判。

c++版

class Solution {
public:
string mp[10] = {"","","abc","def",
                   "ghi","jkl","mno",
                   "pqrs","tuv","wxyz"};
    vector<string> ans;
    vector<string> letterCombinations(string digits) {
        if(digits.empty()) return ans;
        dfs(digits, 0, "");
        return ans;
    }
    void dfs(string digits,int u,string path)
    {
        if(u==digits.size())
        ans.push_back(path);
        else{
            for(auto c:mp[digits[u]-'0'])
            {
                dfs(digits, u+1, path+c);
            }
        }
    }
};

python 版本

class Solution(object):
    def letterCombinations(self, digits):
        mp = ["","","abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"]
        ans = []
 def dfs(strs, u, path):
            if u == len(strs):
                ans.append(path)
                return 
            index  = int(strs[u])
            for c in mp[index]:
                dfs(strs,u + 1, path + c)
 if len(digits) == 0:
 	return ans
 dfs(digits, 0, "")
 return ans
        """
        :type digits: str
        :rtype: List[str]
        """

18. 四数之和

题目描述

给定一个包含 n 个整数的数组 nums 和一个目标值 target,判断 nums 中是否存在四个元素 a,b,c 和 d ,使得 a+ b + c + d 的值与 target 相等?找出所有满足条件且不重复的四元组。
注意: 答案中不可以包含重复的四元组。

示例:

给定数组 nums = [1, 0, -1, 0, -2, 2],和 target = 0。

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

思路

排序+双指针
跟15题的解题思路一样,只不过这里要多循环一层

c++版

class Solution {
public:
    vector<vector<int>> fourSum(vector<int>& nums, int target) {
        vector<vector<int>> ans;
        sort(nums.begin(),nums.end());
        int n = nums.size();
        for(int i = 0; i < n - 3; i++){
            if(i != 0 && nums[i] == nums[i - 1]) continue; //去掉重复元素
            for(int j = i + 1; j < n - 2; j++){
                if(j != i + 1 && nums[j] == nums[j - 1]) continue;//去掉重复元素
                int k = j + 1;
                int u = n - 1;
                while(k < u){
                    int num = nums[i] + nums[j] + nums[k] + nums[u];
                    if(num > target){
                        while(k < u && nums[u] == nums[u - 1])u--;//去掉重复元素
                        u--;
                    }
                    else if(num < target) {
                        while(k < u && nums[k] == nums[k + 1])k++;//去掉重复元素
                        k++;
                    }
                    else{
                        ans.push_back({nums[i],nums[j],nums[k],nums[u]});
                        while(k < u && nums[u] == nums[u - 1])u--;//去掉重复元素
                        while(k < u && nums[k] == nums[k + 1])k++;//去掉重复元素
                        k++;
                        u--;
                    }
                }
            }
        }
        return ans;
    }
};

python版

class Solution:
    def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
        ans = []
        nums.sort()
        n = len(nums)
        for i in range(n - 3):
            if i > 0 and nums[i] == nums[i - 1]:
                continue
            for j in range(i + 1, n - 2):
                if j > i + 1 and nums[j] == nums[j - 1]:
                    continue
                k = j + 1
                u = n - 1
                while(k < u):
                    num = nums[i] + nums[j] + nums[k] + nums[u]
                    if num > target:
                        while(k < u and nums[u] == nums[u - 1]):
                            u -= 1
                        u -= 1
                    elif num < target:
                        while(k < u and nums[k] == nums[k + 1]):
                            k += 1
                        k += 1
                    else:
                        ans.append([nums[i],nums[j],nums[k],nums[u]])
                        while(k < u and nums[k] == nums[k + 1]):
                            k += 1
                        while(k < u and nums[u] == nums[u - 1]):
                            u -= 1
                        k += 1
                        u -= 1
        return ans

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

题目描述

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

示例:

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

当删除了倒数第二个节点后,链表变为 1->2->3->5.
说明:
给定的 n 保证是有效的。
进阶:
你能尝试使用一趟扫描实现吗?

思路

第一种做法:首先循环一遍得到长度L,知道长度后再循环一次得到答案
第二种做法:(快慢指针)我们可以使用两个指针而不是一个指针。第一个指针从列表的开头向前移动 n+1 步,而第二个指针将从列表的开头出发。
现在,这两个指针被 n 个结点分开。我们通过同时移动两个指针向前来保持这个恒定的间隔,直到第一个指针到达最后一个结点。
此时第二个指针将指向从最后一个结点数起的第 n 个结点。我们重新链接第二个指针所引用的结点的 next 指针指向该结点的下下个结点。

c++代码

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode* a = new ListNode(-1);
        a->next = head;
        ListNode* p = a;
        ListNode* q = a;
        for(int i = 0; i <= n; i++)
            p = p->next;
        while(p != NULL){
            q = q->next;
            p = p->next;
        }
        q->next = q->next->next;
        return a->next;
    }
};
a = ListNode(-1)
        a.next = head
        p = a
        q = a
        for i in range(0, n + 1):
            p = p.next
        while(p):
            p = p.next
            q = q.next
        q.next = q.next.next
        return a.next

20. 有效的括号

题目描述

给定一个只包括 ‘(’,’)’,’{’,’}’,’[’,’]’ 的字符串,判断字符串是否有效。 有效字符串需满足:
左括号必须用相同类型的右括号闭合。 左括号必须以正确的顺序闭合。 注意空字符串可被认为是有效字符串。

示例 1:

输入: “()”
输出: true

示例 2:

输入: “()[]{}”
输出: true

示例 3:

输入: “(]”
输出: false

示例 4:

输入: “([)]”
输出: false

示例 5:

输入: “{[]}”
输出: true

思路

栈的应用,遍历字符串,如果当前字符为括号的左半边’(’, ‘[’, ‘{‘就加入到栈中去; 如果当前字符为括号的右半边’)’, ‘]’,
‘}’,则判断是否与栈中的字符匹配,如果匹配的话就出栈。 最后判断栈是否为空即可

c++版本

class Solution {
public:
    bool isValid(string s) {
        //char a[10010];
        stack<char>a;
        for(int i = 0; i < s.size(); i++){
            if(s[i] == '}' &&!a.empty()&& a.top() == '{')
                a.pop();
            else if(s[i] == ']' &&!a.empty()&&a.top() == '[')
                a.pop();
            else if(s[i] == ')' &&!a.empty()&& a.top() == '(')
                a.pop();
            else a.push(s[i]); //a[++t] = s[i];
        }
        if(a.empty()) return true;
        else return false;
    }
};

python版本

class Solution(object):
    def isValid(self, s):
        stack = [""]
        t = 0
        for c in s:
            if t > 0 and c == ')' and stack[t] == '(':
                t -= 1
                stack.pop()
            elif t > 0 and c == '}' and stack[t] == '{':
                t -= 1
                stack.pop()
            elif t > 0 and c == ']' and stack[t] == '[':
                t -= 1
                stack.pop()
            else:
                t += 1
                stack.append(c)
        return True if t == 0 else False
        """
        :type s: str
        :rtype: bool
        """
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值