LeetCode 11 ~ 20

LeetCode 11. 盛最多水的容器

双指针算法。
if(a[i] > a[j]) j --
else i ++
这一步为本题的核心,接着迭代更新最大值即可

class Solution {
public:
    int maxArea(vector<int>& height) {
        int res = 0;
        for(int i = 0, j = height.size() - 1; i < j;) {
            res = max(res, min(height[i], height[j]) * (j - i));
            if(height[i] > height[j]) j -- ;
            else i ++ ;
        }
        return res;
    }
};

LeetCode 12. 整数转罗马数字

  1. 小的数字在大的数字的右边,所表示的数等于这些数字相加得到的数,如:VIII=8, XII=12
  2. 小的数字在大的数字的左边(限于 IV、IX、XL、XC、CD和CM),所表示的数等于大数减小数得到的数,如:IV=4, IX=9
  3. 相同的数字连写,所表示的数等于这些数字相加得到的数,如:III=3
  4. 正常使用时,连写的数字重复不得超过三次
    根据以上几点规律,可以将罗马数字整理出下面的表格
MCMDCDCXCLXLXIXVIVI
1000900500400100905040109541

可以根据罗马数字的规律,优先使用数值较大的单位将整数转换成罗马数字

class Solution {
public:
    string intToRoman(int num) {
        int values[] = {
            1000,
            900, 500, 400, 100,
            90, 50, 40, 10,
            9, 5, 4, 1
        };
        string reps[] = {
            "M",
            "CM", "D", "CD", "C",
            "XC", "L", "XL", "X",
            "IX", "V", "IV", "I"
        };

        string res;
        for(int i = 0; i <= 12; i ++ ) {
            while(num >= values[i]) {
                num -= values[i];
                res += reps[i];
            }
        }

        return res;
    }
};

LeetCode 13. 罗马数字转整数

思路类比LeetCode 12. 整数转罗马数字,使用一张哈希表记录各个罗马数字对应的数值
线性扫描字符串,如果发现 s[i + 1] 的数值比s[i]的数值大,则累加s[i + 1] - s[i] 这个差值,否则累加 s[i] 即可

class Solution {
public:
    int romanToInt(string s) {
        unordered_map<char, int> values;
        values['I'] = 1;
        values['V'] = 5;
        values['X'] = 10;
        values['L'] = 50;
        values['C'] = 100;
        values['D'] = 500;
        values['M'] = 1000;

        int res = 0;
        for(int i = 0; i < s.size(); i ++ ) {
            if(i + 1 < s.size() && values[s[i]] < values[s[i + 1]])
                res -= values[s[i]];
            else
                res += values[s[i]];
        }
        return res;
    }
};

LeetCode 14. 最长公共前缀

暴力枚举
可以从字符串数组里面找到最短的那个字符串,并记录长度为m
将答案从这个最短字符串的第一位开始枚举到第m位判断其他字符串是否有这样的前缀即可

class Solution {
public:
    string longestCommonPrefix(vector<string>& strs) {
        string res;
        if(strs.size() == 0) return res;
        for(int i = 0; ; i ++ ) {
            if(i >= strs[0].size()) return res;
            char c = strs[0][i];
            for(auto& str : strs)
                if(str.size() <= i || str[i] != c) 
                    return res;
            res += c;
        }
        return res;
    }
};

LeetCode 15. 三数之和

排序 + 双指针

  1. 枚举每个数,表示该数的nums[i] 已确定, 通过双指针 l = i + 1r = n - 1 往中间靠拢,直到找到nums[i] + nums[l] + nums[r] == 0所有符合条件的搭配
  2. 在找符合条件搭配的过程中,假设sum = nums[i] + nums[l] + nums[r]
    sum > 0,则r往左走,使sum变小
    sum < 0,则l往右走,使sum变大
    sum == 0,则表示找到了与nums[i]搭配的组合nums[l]nums[r],存到res中
  3. 判重处理
    确定好nums[i]时,l 需要从i + 1开始
    nums[i] == nums[i - 1],表示当前确定好的数与上一个一样,需要直接continue
    当找符合条件搭配时,即sum == 0,需要对相同的nums[l]和nums[r]进行判重出来
class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        vector<vector<int>> res;
        sort(nums.begin(), nums.end());
        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; j ++ ) {
                if(j > i + 1 && nums[j] == nums[j - 1]) continue;
                while(j < k - 1 && nums[i] + nums[j] + nums[k - 1] >= 0) k -- ;
                if(nums[i] = nums[j] + nums[k] == 0) {
                    res.push_back({nums[i], nums[j], nums[k]});
                }
            }
        }
        return res;
    }
};

LeetCode 16. 最接近的三数之和

排序 + 双指针

  1. 枚举每个数,表示该数的nums[i] 已确定, 通过双指针 l = i + 1r = n - 1 往中间靠拢,直到找到nums[i] + nums[l] + nums[r] == sum所有情况中最接近target的sum,更新res
  2. 在找符合条件搭配的过程中,假设sum = nums[i] + nums[l] + nums[r]
    sum > target,则r往左走,使sum变小
    sum < target,则l往右走,使sum变大
    sum == target,则表示找到了与nums[i]搭配的组合nums[l]nums[r],直接返回
  3. 判重处理
    确定好nums[i]时,l 需要从i + 1开始
    nums[i] == nums[i - 1],表示当前确定好的数与上一个一样,需要直接continue
class Solution {
public:
    int threeSumClosest(vector<int>& nums, int target) {
        sort(nums.begin(), nums.end());
        pair<int, int> res(INT_MAX, INT_MAX);
        for(int i = 0; i < nums.size(); i ++ )
            for(int j = i + 1, k = nums.size() - 1; j < k; j ++ ) {
                while(k - 1 > j && nums[i] + nums[j] + nums[k - 1] >= target) k -- ;
                int s = nums[i] + nums[j] + nums[k];
                res = min(res, make_pair(abs(s - target), s));
                if(k - 1 > j) {
                    s = nums[i] + nums[j] + nums[k - 1];
                    res = min(res, make_pair(target - s, s));
                }
            }
        return res.second;  
    }
};

LeetCode 17. 电话号码的字母组合

  1. 先把数字和字符存进两个数组中相互映射
  2. 通过深度优先搜索进行遍历
  3. 当达到对应长度时将当前字符串存进数组中
class Solution {
public:
    vector<string> ans;
    string strs[10] = {
        "", "", "abc", "def",
        "ghi", "jkl", "mno",
        "pqrs", "tuv", "wxyz",
    };

    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 : strs[digits[u] - '0'])
            dfs(digits, u + 1, path + c);
        }
    }
};

LeetCode 18. 四数之和

排序 + 双指针

1、与三数之和操作类似,枚举每两个数,表示该数nums[i]nums[j]已被确定,在排序后的情况下,通过双指针l,r分别从左边l = i + 1和右边n - 1往中间靠拢,找到nums[i] + nums[j] + nums[l] + nums[r] == target的所有符合条件的搭配
2、在找符合条件搭配的过程中,假设sum = nums[i] + nums[j] + nums[l] + nums[r]
sum > target,则r往左走,使sum变小
sum < target,则l往右走,使sum变大
sum == target,则表示找到了与nums[i]搭配的组合nums[l]和nums[r],存到ans中
3、判重处理
确定好nums[i]时,l 需要从i + 1开始
nums[i] == nums[i - 1],表示当前确定好的数与上一个一样,需要直接continue
nums[j] == nums[j - 1],表示当前确定好的数与上一个一样,需要直接continue
当找符合条件搭配时,即sum == 0,需要对相同的nums[l]和nums[r]进行判重出来

class Solution {
public:
    vector<vector<int>> fourSum(vector<int>& nums, int target) {
        sort(nums.begin(), nums.end());
        vector<vector<int>> res;
        for (int i = 0; i < nums.size(); i ++ ) {
            if (i && nums[i] == nums[i - 1]) continue;
            for (int j = i + 1; j < nums.size(); j ++ ) {
                if (j > i + 1 && nums[j] == nums[j - 1]) continue;
                for (int k = j + 1, u = nums.size() - 1; k < u; k ++ ) {
                    if (k > j + 1 && nums[k] == nums[k - 1]) continue;
                    while (u - 1 > k && nums[i] + nums[j] + nums[k] + nums[u - 1] >= target) u -- ;
                    if (nums[i] + nums[j] - target == -nums[k] - nums[u]) {
                        res.push_back({nums[i], nums[j], nums[k], nums[u]});
                    }
                }
            }
        }
        return res;
    }
};

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

先遍历一遍链表记录链表总长度,在第二次遍历的时候将倒数第N个节点删除

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int k) {
        auto dummy = new ListNode(-1);
        dummy -> next = head;

        int n = 0;
        for(auto p = dummy; p; p = p -> next) n ++ ;

        auto p = dummy;
        for(int i = 0; i < n - k - 1; i ++ ) p = p -> next;
        p -> next = p -> next -> next;
        
        return dummy -> next;
    }
};

LeetCode 20. 有效的括号

栈的简单应用

class Solution {
public:
    bool isValid(string s) {
        stack<char> stk;

        for (auto c : s) {
            if (c == '(' || c == '[' || c == '{') stk.push(c);
            else {
                if (stk.size() && abs(stk.top() - c) <= 2) stk.pop();
                else return false;
            }
        }

        return stk.empty();
    }
};
class Solution {
public:
    bool isValid(string s) {
        int len = s.length();
        if(len % 2) return false;
        stack<int> st;
        for(int i = 0; i < len; i ++ )
        {
            if(s[i] == '(' || s[i] == '[' || s[i] == '{')
                st.push(s[i]);
            else if(!st.empty())
            {
                if(s[i] == ')' && st.top() == '(')
                    st.pop();
                else if(s[i] == ']' && st.top() == '[')
                    st.pop();
                else if(s[i] == '}' && st.top() == '{')
                    st.pop();
                else return false;
            }else return false;
        }
        if(st.empty()) return true;
        return false;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值