LeetCode C/C++语言版详解(16-20)

LeetCode C/C++语言版详解(16-20)

PS:分享下C转C++的原因

为了节省时间,我还是快速上手了一下C++。我发现只要学习过C语言,C++的语句有些不看解释都能看得懂它的意思,这就很舒服。我要分享一下一篇优秀的文章,《从放弃C语⾔到使⽤C++刷算法的简明教程》by 柳婼,这篇文章详细的讲了一下C和C++优缺点的对比,因为在CSDN上分享资源不能设置0积分,所以我直接用百度网盘链接分享了

链接:https://pan.baidu.com/s/1Ow8LWnbgNuyPI0naxPaN9A
提取码:legk

16 最接近的三数之和

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

例如,给定数组 nums = [-1,2,1,-4], 和 target = 1.

与 target 最接近的三个数的和为 2. (-1 + 2 + 1 = 2).

题目越往后,我发现根本就没有C语言实现的博客了,我来开荒了!

int inc (const void * a,const void *b)
{
    return *(int *)a - *(int *)b;
}

int threeSumClosest(int* nums, int numsSize, int target){
    int result = 0;
    if(numsSize <= 3)// 判断是否小于三,小于就直接返回相加的值
    {
        for(int i = 0; i < numsSize; i++)
            result += nums[i];
        return result;
    }
    qsort(nums, numsSize, sizeof(int), inc);// qsort函数(数组,数组个数,所占字节数,内置函数),不懂可以自己去搜一下,这里的调用的函数是上面的inc
    result = nums[0] + nums[1] + nums[2];// 初始化的结果值
    int dis = abs(result-target);// 与target相减后取绝对值,然后循环比较,绝对值越小,则相加的数越接近
    for(int i = 0; i < numsSize; i++)
    {
        int j = i + 1;
        int k = numsSize - 1;
        while(j < k)
        {
            int temp = abs(nums[i] + nums[j] + nums[k] - target);
            if(temp < dis)// 优先判断是否最接近
            {
                dis = temp;
                result = nums[i] + nums[j] + nums[k];
            }
            if(nums[i] + nums[j] + nums[k] < target) // 相加比taget小,则j向后移
            {
                j += 1;
            }
            else if(nums[i] + nums[j] + nums[k] > target)// 相加比taget大,则k向前移
            {
                k -= 1;
            }
            else// 如果刚好,那就是相等,直接返回
            {
                return nums[i] + nums[j] + nums[k];
            }
        }
    }
    return result;
}


17 电话号码的字母组合

给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。

给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。

在这里插入图片描述

示例:

输入:“23”
输出:[“ad”, “ae”, “af”, “bd”, “be”, “bf”, “cd”, “ce”, “cf”].
说明:
尽管上面的答案是按字典序排列的,但是你可以任意选择答案输出的顺序。

递归

/**
 * Return an array of size *returnSize.
 * Note: The returned array must be malloced, assume caller calls free().
 */
void save(char* digits, char** map, char* before, int len, int start, char*** result, int* size) {
    if(start == len)j
    {
        (*size)++;
        result[0] = (char**)realloc(result[0], *size * sizeof(char*));// 不懂可以去查一下malloc、realloc、calloc的区别
        result[0][*size - 1] = (char*)malloc((len + 1) * sizeof(char));
        memcpy(result[0][*size - 1], before, len * sizeof(char));
        result[0][*size - 1][len] = '\0';
        return;
    }
    char* temp = map[digits[start] - '1'];// 1对应的是没有,所以对应下标为0,故-‘1’
    while(*temp)// 遍历这一段字符串的每一个字符
    {
        before[start] = *temp;//并且将该字符为开头的字符串放入before中
        save(digits, map, before, len, 1 + start, result, size);
        /*
        *start初值为0,当它遍历第一层,则1 + start,遍历第二层则为1 + (1 + start)
        *在上面的if判断中,start如果跟len长度相等,就往result存值
        */
        temp++;
    }
}
char** letterCombinations(char* digits, int* returnSize) {
    int len = strlen(digits);
    *returnSize = 0;// 我执行了几遍并且打印出来都是随机的,所以returnSize给的时候是个随机数,所以要初始化一下
    if(len == 0)
        return NULL;
    char* map[9] = {"", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"};// 初始化1到9对应的字母
    char** result = NULL;
    char* before = (char*)malloc(len * sizeof(char));
    save(digits, map, before, len, 0, &result, returnSize);
    /*
    *传递digit这个字符串,思路从左到右相减‘1’,来得到其map值
    *map存储1-9中的对应字母字符串
    *before里存的是个遍历中的1-9相对应的一个字符串,比如 2 对应的 “abc”,那么before在对应2的时候里面存储的就是“abc”
    *len是对应的长度,如果是输入了两个数字,那么len就是2,如果输入为三个数字,那么len就是3,
    *因为输入两个数字,拼出来的是两位的字母,输入三位则是三位的字母
    *0是当前起始位置
    *result就是用来存放返回的所有值的
    *returnSize就是递归函数中对应的size,用来存放有多少个不同值
    */
    return result;
}

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]
]

四数之和就是在三数之和的基础上再套一层循环即可

class Solution {
public:
    vector<vector<int>> fourSum(vector<int>& nums, int target) {
        sort(nums.begin(),nums.end());
        int n = nums.size();
        set<vector<int> > s;
        for(int i = 0;i < n;i++)
        {
            if(i > 0 && nums[i - 1] == nums[i])
                continue;
            for(int j = i + 1;j < n;j++)
            {
                int start = j + 1,end = n - 1;
                while(start < end)
                {
                    int temp = nums[start] + nums[end] + nums[i] + nums[j];
                    if(temp == target && i < j)
                    {
                        s.insert(vector<int>{nums[start],nums[end],nums[i],nums[j]});
                        while(start < end && nums[start] == nums[start + 1])
                            start++;
                        while(start < end && nums[end] == nums[end - 1])
                            end--;
                        start++;
                        end--;
                    }
                    else if(temp > target)
                        end--;
                    else
                        start++;
                }
            }
        }
        return vector<vector<int> >(s.begin(),s.end());
    }
};

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

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

示例:

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

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

给定的 n 保证是有效的。

进阶:

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

这个思路是真的机智!!!

/**
 * 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) {
        if(!head | !head -> next) return NULL;// 判断是否只有0或1个
        ListNode * fast = head, *slow = head;
        for(int i = 0; i < n; i++)// 首先你想取倒数第几个的数值,那么,我先把这个空隙放好,就是这个fast
        {
            fast = fast -> next;
        }
        if(!fast)
        {
            return head -> next;
        }
        
        while(fast -> next)// 然后从这个空隙一直循环到没有位置,这样我的slow就会到达倒数第那个值的地方了
        {
            fast = fast -> next;
            slow = slow -> next;
        }
        slow -> next = slow -> next -> next;// 直接将它的下一个等于下下个就行
        return head;
    }
};

20 有效的括号

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

有效字符串需满足:

左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
注意空字符串可被认为是有效字符串。

示例 1:

输入: “()”
输出: true
示例 2:

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

输入: “(]”
输出: false
示例 4:

输入: “([)]”
输出: false
示例 5:

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

思路是如果成对就把这两个消掉

class Solution {
public:
    bool isValid(string s) {
        int i = 0;
        while(i<s.length())// 如果有配对则将s去掉这两个,并且判断i是否往前移,如果没有配对,则i向后走
        {
            if(s[i+1]-s[i] == 1 || s[i+1]-s[i] ==2)// 我查了一下ASCII表,除了()以外,其他两种括号都间隔一个字符,所以相邻是否为1或者为2,如果成立则这两个消除
            {
               s.replace(i,2,"");
               if(i>0)
               {
                   i--;
               }
            }
            else
            {
                i++;
            }        
        }
        if(s != "")// 如果s中还有,证明不配对,反之则配对
            return false;
        else
            return true;
    }
};
  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

痴心的萝卜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值