LeetCode Hot 100(三) C++版

11 篇文章 1 订阅


LeetCode Top 100 题解


1.三数之和

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

示例:
给定数组 nums = [-1, 0, 1, 2, -1, -4],
满足要求的三元组集合为:
[
[-1, 0, 1],
[-1, -1, 2]
]

判断nums中三元素之和为0,除过三者都为0的情况之外,还包括正负数,所以先先选定一个数,然后再去找另外两个数,这两数之和为选定的数的相反数即可,所以将数组排序,然后用双指针以线性时间复杂度来进行遍历结果。

class Solution {
public:
	vector<vector<int>> threeSum(vector<int>& nums) {
		vector<vector<int> > res;

		if (nums.size() < 3)
			return res;

		sort(nums.begin(), nums.end());
        if((nums[0] == nums[nums.size() - 1]) && nums[0] == 0)
        {
           res.push_back({0, 0, 0});
           return res;
        }
		const int target = 0;//目标值

		auto last = nums.end();
		for (auto a = nums.begin(); a < prev(last, 2); ++a)//遍历到倒数第三个即可
		{
			auto b = next(a);
			auto c = prev(last);
			while (b < c)
			{
				if (*a + *b + *c < target)
				{
					++b;//趋向于大数
				}
				else if (*a + *b + *c > target)
				{
					--c;//趋向于小数
				}
				else
				{
					res.push_back({*a, *b, *c});
					++b;
					--c;
				}
			}
		}

		sort(res.begin(), res.end());
		res.erase(unique(res.begin(), res.end()), res.end());//去重
		return res;

	}
};

还可以进行剪枝优化,即当遍历到正数的时候就break,因为若选定的第一个数是正数,对于已经排好序的数组来说,之后的数字都是正数,其和不为0;在处理重复的问题中,从第二个数开始,如果和前面的数字相等就跳过。

class Solution {
public:
	vector<vector<int>> threeSum(vector<int>& nums) {
		vector<vector<int>> res;

		sort(nums.begin(),nums.end());

		if (nums.empty() || nums.back() < 0 || nums.front() > 0)
			return {};

		for (int k = 0; k < (int)nums.size() - 2; ++k)
		{
			if (nums[k] > 0)//剪枝
				break;

			if (k > 0 && nums[k] == nums[k - 1])//去重
				continue;

			int targrt = 0 - nums[k], i = k + 1, j = (int)nums.size() - 1;
			while (i < j)
			{
				if (nums[i] + nums[j] == targrt)
				{
					res.push_back({ nums[k],nums[i],nums[j]});

					while (i < j && nums[i] == nums[i + 1])//去重
						++i;

					while (i < j && nums[j] == nums[j - 1])//去重
						--j;
                    
                    ++i;
                    --j;
				}
				else if (nums[i] + nums[j] < targrt)
				{
					++i;
				}
				else
					--j;
			}
		}

		return res;
	}
};
2.电话号码的字母组合

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

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

利用递归Recursion来解此题,建立字典keyLetters,保存每个数字代表的字符串,利用index变量来记录当前生成的字符串的字符数,若index等于digits的长度,就将其加入strs中,然后返回。通过digits中的数组访问字符串,遍历取出字符加入当前的组合中即可。

string keysLetters[10] = {"", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"}; 

class Solution {
public:
    void ConLetters(const string& digits, size_t index, const string& str, vector<string>& strs)
    {
       if(index == digits.size())
       {
           strs.push_back(str);
           return;
       }
        
        //获取数字的字母串
        string letters = keysLetters[digits[index] - '0'];
        
        for(size_t i = 0; i < letters.size(); i++)
        {
            ConLetters(digits, index + 1, str + letters[i], strs);
        }
    }
    
    vector<string> letterCombinations(string digits) {
        vector<string> strs;
        
        if(digits.empty())  
        {
            return strs;
        }
        
        
        size_t index = 0;
        string str;
        ConLetters(digits, index, str, strs);
        return strs;   
    }
};

利用迭代Iterative也可以解此题,遍历digit中所有数字时,建立临时字符串数组tmp,通过数字找到keyLetters中的字符串,然后遍历取出字符串中的所有字符,再遍历当前结果res中的每一个字符串,将字符加到其后,保存到临时字符串数组中,取出的字符串letters遍历结束后,将tmp赋值给res即可。

string keysLetters[10] = { "", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz" };

class Solution {
public:
	vector<string> letterCombinations(string digits) {
		if (digits.empty())
		{
			return {};
		}

		vector<string> strs{""};
		for (int i = 0; i < digits.size(); ++i)
		{
			vector<string> tmp;
			string letters = keysLetters[digits[i] - '0'];

			for (int j = 0; j < letters.size();++j)
			{
				for (string str : strs)
				{
					tmp.push_back(str + letters[j]);
				}
			}

			strs = tmp;

		}
		return strs;
	}
}; 
3.删除链表的倒数第N个节点

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

给定一个链表: 1->2->3->4->5, 和 n = 2.
当删除了倒数第二个节点后,链表变为 1->2->3->5.

限定n是有效的,所以n不会超过链表长度。使用两个指针pre和cur,先让cur向前走n步,若cur为空,则n为链表长度,则需要移除的为首结点,直接返回head->next,若不为空,则让pre和cur同时走,直到cur为最后一个元素,然后删除pre指向的结点的下一个结点即可。

/**
 * 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->next) 
           return NULL;
        
        ListNode *pre = head, *cur = head;
        for (int i = 0; i < n; ++i) 
        {
            cur = cur->next;
        }
          
        if (!cur) 
            return head->next;
        
        while (cur->next) {
           cur = cur->next;            
           pre = pre->next;
         }  
        
        pre->next = pre->next->next;        
        return head;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值