LeetCode刷题总结1

1. Two Sum

Given an array of integers, return indices of the two numbers such that they add up to a specific target.
You may assume that each input would have exactly one solution, and you may not use the same element twice.
Example:
Given nums = [2, 7, 11, 15], target = 9,
Because nums[0] + nums[1] = 2 + 7 = 9,
return [0, 1].

1、 暴力破解

遍历所有组合可能性,其中数字使用了两次,应该说不满足题目要求的,但能通过所有测试。。

class Solution {
public:
	vector<int> twoSum(vector<int>& nums, int target) {
		vector<int> ret;
		int i, j;
		int length = nums.size();
		for (i = 0; i < length; i++) {
			for (j = i + 1; j < length; j++) {
				if (nums[i] + nums[j] == target) {
					ret.push_back(i);
					ret.push_back(j);
					break;
				}
			}
		}
		return ret;
	}
};

2、滑动窗口结合unordered_map

键值对为元素值与对应下标,采用两遍哈希表或一遍哈希表。两遍哈希表属于先建立后查找,一遍哈希表属于边建立边查找。

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        vector<int> ret;
        if(nums.size() <2)
            return ret;
        unordered_map<int, int> map; // c++11中unordered_map更合适,hash_map已放弃
        for(size_t pos = 0; pos < nums.size(); pos++){ // 这里采用先初始化添加元素
            map[nums[pos]] = pos;
        }
        for(size_t pos = 0; pos < nums.size(); pos++){ // 然后查找元素
            int findkey = target - nums[pos];
            auto itr = map.find(findkey);
            if(itr != map.end() && pos != itr->second){
                ret.push_back(pos);
                ret.push_back(itr->second);
                break;
            }
        }
        return ret;
        // for(size_t i = 0; i<nums.size(); i++){ // 这里属于一边查找一边添加元素
        //     auto itr = map.find(target - nums[i]);
        //     if(itr == map.end() ){
        //         map.insert(pair<int, int>(nums[i], i) );
        //         //map[nums[i]] = i;
        //     }
        //     else{
        //         ret.push_back(itr->second);
        //         ret.push_back(i);
        //         break;
        //     }
        // }
        // return ret;
    }
};

2. Add Two Numbers

You are given two non-empty linked lists representing two non-negative integers. The digits are stored in reverse order and each of their nodes contain a single digit. Add the two numbers and return it as a linked list.
You may assume the two numbers do not contain any leading zero, except the number 0 itself.
Example:
Input: (2 -> 4 -> 3) + (5 -> 6 -> 4)
Output: 7 -> 0 -> 8
Explanation: 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) {
        if(l1 == nullptr) // 任意一个列表为空的情况
            return l2;
        if(l2 == nullptr)
            return l1;      
        ListNode *ret, *head;
        head = ret = new ListNode(0);
        int addFlag = 0; // 初始不产生进位
        while(l1 != nullptr || l2 != nullptr){
            int sum = 0;
            if(l1 != nullptr){ // 列表长度相等或其中一个列表较长
                sum += l1->val;
                l1 = l1->next;
            }
            if(l2 != nullptr){
                sum += l2->val;
                l2 = l2->next;
            }
            sum += addFlag;
            ret->next = new ListNode(sum%10);
            addFlag = sum/10; // 设置新的进位
            ret = ret->next;
        }
        if(addFlag == 1) // 两个列表长度相等且最高位产生进位,需要追加一个进位结点
            ret->next = new ListNode(1);
        return head->next;
    }
};

3. Longest Substring Without Repeating Characters

Given a string, find the length of the longest substring without repeating characters.
Example 1:
Input: “abcabcbb”
Output: 3
Explanation: The answer is “abc”, with the length of 3.
Example 2:
Input: “bbbbb”
Output: 1
Explanation: The answer is “b”, with the length of 1.
Example 3:
Input: “pwwkew”
Output: 3
Explanation: The answer is “wke”, with the length of 3.
Note that the answer must be a substring, “pwke” is a subsequence and not a substring.

1、自己原始的暴力破解,与方法2的暴力破解相比,把判断allUnique函数直接写到lengthOfLongestSubstring函数中,反而能勉强通过所有测试,但是时间消耗增加了近40倍,内存近20倍。

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        if(s.size() < 2)
            return s.size();
        int maxlen = 0;
        for (size_t i = 0; i < s.length()-1; i++) {
            unordered_set<char> set;
            for (size_t j = i; j < s.length(); j++) {
                if(set.find(s[j]) != set.end() )
                    break;
                set.insert(s[j]);
                maxlen = set.size() > maxlen ? set.size() : maxlen;
            }
        }
        return maxlen;
    }
};

2、滑动窗口,采用了set作窗口(数组也应该可以),右边添加字符,左边删除字符直到set里面没有重复字符,那么最大无重复字符串长度,即为添加字符过程动态窗口的最大宽度。这里涉及到最恶化情况,l与r分别需要扫过一遍字符串。

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        int ans = 0;
        int len = s.length();
        if(len < 2)
            return len;
        unordered_set<char> set;
        int l = 0, r = 0; // l 为滑动窗口左, r为右;
        while(l < len && r < len){
            if(set.find(s[r]) == set.end() ){
                set.insert(s[r++]);
                int tmp = set.size();
                ans = ans > tmp ? ans : tmp;
            }
            else
                set.erase(s[l++]);
        }
        return ans;
        // for(int i = 0; i <= s.length()-1; i++){ // 暴力破解失败,解释是题目更新后通不过
        //     for(int j = i+1; j <= s.length(); j++){
        //         if(!allUnique(s, i, j)) // 若为重复子字符串就结束当前循环
        //             break;
        //         ans = ans > (j-i) ? ans : (j-i);
        //     }
        // }
        // return ans;
    }
    // 采用两种数据结构的判断函数,分别为set和map,实际map的键值对中的值没发挥作用
    bool allUnique(string s, int start, int end){
        unordered_set<char> set;
        for(size_t i = start; i < end; i++){
            if(set.find(s[i]) != set.end() )
                return false;
            set.insert(s[i]);
        }
        return true;
    }
    // bool allUnique(string s, int start, int end){
    //     unordered_map<char, int> map; // 这里map相对于set意义不大
    //     for(size_t i = start; i < end; i++){
    //         auto itr = map.find(s[i]);
    //         if(itr != map.end() && itr->second != i)
    //             return false;
    //         map[s[i]] = i;
    //     }
    //     return true;
    // }
};

3、优化的滑动窗口,原始窗口是右边是一次次添加,左边是一次次删除,直到达到要求的不重复字符位置,改进的思想是左边一次就移动到指定位置,那么采用map键值对来存储字符和字符下标。

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        int ans = 0;
        int len = s.length();
        if(len < 2)
            return len;
        unordered_map<char, int> map;
        for(int i = 0, j = 0; j < len; j++){
            auto itr = map.find(s[j]);
            if(itr != map.end() ){
                int newI = itr->second;
                i = newI > i ? newI:i; // 这里的目的是防止i向左移动,因为哈希表中左边的重复字符可能出现多次。
            }
            ans = ans > (j-i+1)?ans:(j-i+1);
            map[s[j]] = j+1;
        }
        return ans; 
};

附:
1、参考C++ STL 之 unordered_set 使用(包括unordersd_map)链接地址:https://blog.csdn.net/qq_32172673/article/details/85160180

为了以后复习巩固,如有错误请见谅。
贵有恒,何必三更起五更睡;最无益,只怕一日曝十日寒。

发布了3 篇原创文章 · 获赞 0 · 访问量 93

猜你喜欢

转载自blog.csdn.net/weixin_43271235/article/details/104857967
今日推荐