Leetcode 136 2// 动态规划打家劫舍 198 213 337 // 18// 字符串 344 541

本文介绍了LeetCode中几种常见的算法问题解决方案,包括使用位操作求单数元素,利用哈希映射解决两数之和问题,动态规划策略解决房子窃贼系列问题,以及处理链表和字符串反转的技巧。这些方法展示了在解决编程挑战时的高效策略。
摘要由CSDN通过智能技术生成

136. Single Number

1.位操作,用异或

class Solution {
public:
    int singleNumber(vector<int>& nums) {
        int res = 0;
        for(int num:nums){
            res ^= num;
        }

        return res;
    }
};

2.使用map(使用了不恒定的额外空间)

class Solution {
public:
    int singleNumber(vector<int>& nums) {
        unordered_map<int, int> map;
        for(auto num:nums){
            map[num]++;
        }
        for(auto val:map){
            if(val.second == 1)
                return val.first;
        }

        return -1;
    }
};

3.排序后看前后两个元素是否一样,使用了恒定的额外空间

2. Add Two Numbers

class Solution {
public:
    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
        ListNode* dummy = new ListNode(-1);
        ListNode* p = dummy;
        ListNode* p1 = l1;
        ListNode* p2 = l2;
        int carry = 0; // 进位

        while(p1 != NULL || p2 != NULL || carry != 0){
            int val = carry;
            if(p1 != NULL){
                val += p1->val;
                p1 = p1->next;
            }
            if(p2 != NULL){
                val += p2->val;
                p2 = p2->next;
            }
            carry = val/10;
            val = val%10;
            p->next = new ListNode(val);
            p = p->next;
        }

        return dummy->next;
    }
};

注意循环的时候要加上条件carry != 0

198. House Robber

class Solution {
public:
    int rob(vector<int>& nums) {
        if(nums.size() == 1) return nums[0];
        vector<int> dp(nums.size(),0);
        dp[0] = nums[0];
        dp[1] = max(nums[0], nums[1]);
        for(int i=2; i<nums.size(); i++){
            dp[i] = max(dp[i-1], dp[i-2]+nums[i]);
        }

        return dp[nums.size()-1];
    }
};

213. House Robber II

class Solution {
public:
    int rob(vector<int>& nums) {
        if(nums.size() == 1) return nums[0];
        int res1 = robVal(nums, 0, nums.size()-2);
        int res2 = robVal(nums, 1, nums.size()-1);

        return max(res1, res2);
    }

    int robVal(vector<int>& nums, int first, int last){
        if(first-last == 0) return nums[first];
        vector<int> dp(nums.size(), 0);
        dp[first] = nums[first];
        dp[first+1] = max(nums[first], nums[first+1]);
        for(int i=first+2; i<=last; i++){
            dp[i] = max(dp[i-1], dp[i-2]+nums[i]);
        }

        return dp[last];

    }
};

若为环形只有三种可能

1)不考虑第一个

2)不考虑最后一个

3)第一个和最后一个都不考虑(但在这道题中,这个一定是最小的,所以省略)

337. House Robber III

class Solution {
public:
    int rob(TreeNode* root) {
        vector<int> res = robTree(root);
        return max(res[0], res[1]);
    }

    vector<int> robTree(TreeNode* cur){
        if(cur == NULL) return vector<int>{0,0};

        vector<int> left = robTree(cur->left);
        vector<int> right = robTree(cur->right);
        //偷了的值
        int val1 = cur->val + left[0] +right[0];
        //没偷的值
        int val2 = max(left[0], left[1]) + max(right[0], right[1]);
        return {val2, val1};
    }
};

只能大概理解思路

思路:

这里的dp数组是记录每个节点的两个状态,0为没偷时的最大值,1为偷了时候的最大值。

因为这里要求一个节点偷与不偷的值,所以采用后续遍历(从下往上)

tips:这里写代码要注意一个小点,robTree函数return的值要符合自己的定义,即val2是没偷的,val1是偷的,所以要返回的是{val2, val1}, 不要写反了

18. 4Sum

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

                        left++;
                        right--;
                
                }
                }

            }

        }

        return res;
    }
};

1.运用双指针,两次修枝即可

2.四数和可能会溢出,要用一个(long)

344. Reverse String

class Solution {
public:
    void reverseString(vector<char>& s) {
        int left = 0, right = s.size()-1;
        while(left < right){
            char tmp = s[left];
            s[left] = s[right];
            s[right] = tmp;
            left++;
            right--;
        }
    }
};

541. Reverse String II

class Solution {
public:
    string reverseStr(string s, int k) {
        for(int i=0; i<s.size();i = i+2*k){
            if(i+k<=s.size()){
                reverse(s.begin()+i, s.begin()+i+k);
            }else{
                reverse(s.begin()+i, s.end());
            }
        }
        return s;
    }
};

要注意会出现不够k个的情况

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值