算法训练营 Day 6

1、四数相加II

#include <iostream>
#include <unordered_map>
#include <vector>

using namespace std;

class Solution {
public:
    int fourSumCount(vector<int> &A, vector<int> &B, vector<int> &C, vector<int> &D) {
        unordered_map<int, int> umap; //key:a+b的数值,value:a+b数值出现的次数
        // 遍历A和B数组,统计两个数组元素之和,和出现的次数,放到map中
        for (int a: A) {
            for (int b: B) {
                umap[a + b]++; //如果键不存在,会创建一个新的键值对,且++后为1
            }
        }
        int count = 0; // 计数器,统计 a+b+c+d=0 出现的次数
        // 在遍历C和D数组,找到如果 0-(c+d) 在map中出现过的话,就把map中key对应的value也就是出现次数统计出来。
        for (int c: C) {
            for (int d: D) {
                if (umap.find(-(c + d)) != umap.end()) {
                    count += umap[-(c + d)];
                }
            }
        }
        return count;
    }
};

int main() {
    vector<int> A{1, 2};
    vector<int> B{-2, -1};
    vector<int> C{-1, 2};
    vector<int> D{0, 2};

    Solution solution;
    cout << solution.fourSumCount(A, B, C, D);
}

2、赎金信

先用两层for循环暴力解法:

#include <iostream>

using namespace std;

class Solution {
public:
    bool canConstruct(string ransomNote, string magazine) {
        if (ransomNote.size() > ransomNote.size())
            return false;
        for (int i = 0; i < magazine.length(); ++i) {
            for (int j = 0; j < ransomNote.length(); ++j) {
                if (magazine[i] == ransomNote[j]) {
                    ransomNote.erase(ransomNote.begin() + j); // ransomNote删除这个字符
                    break;
                }
            }
        }
        return ransomNote.empty(); //如果为空,返回true
    }
};

int main() {
    string str1 = "aa";
    string str2 = "aab";

    Solution solution;
    cout << solution.canConstruct(str1, str2);
}

利用哈希法:

#include <iostream>

using namespace std;

class Solution {
public:
    bool canConstruct(string ransomNote, string magazine) {
        int record[26]{0}; //因为只有小写字母
        if (ransomNote.size() > magazine.size())
            return false;

        for (int i = 0; i < magazine.length(); ++i)
            record[magazine[i] - 'a']++;

        for (int j = 0; j < ransomNote.length(); ++j) {
            record[ransomNote[j] - 'a']--;
            // 如果小于零说明ransomNote里出现的字符,magazine没有
            if (record[ransomNote[j] - 'a'] < 0)
                return false;
        }
        return true;
    }
};

int main() {
    string str1 = "aa";
    string str2 = "aab";

    Solution solution;
    cout << solution.canConstruct(str1, str2);
}

3、三数之和

先用暴力解法,这种方法需要考虑复杂的边界情况,极为繁琐:

#include <iostream>
#include <unordered_set>
#include <vector>

using namespace std;

class Solution {
public:
    vector<vector<int>> threeSum(vector<int> &nums) {
        vector<vector<int>> result;
        sort(nums.begin(), nums.end());
        // a = nums[i], b = nums[j], c = -(a + b)
        for (int i = 0; i < nums.size(); i++) {
            if (nums[i] > 0) // 排序之后如果第一个元素已经大于零,那么不可能凑成三元组,这里始终保持nums[i]是最小值
                break;

            if (i > 0 && nums[i] == nums[i - 1])  //三元组元素a去重
                continue; //pass

            unordered_set<int> uset; //特点是无序,元素无重复
            for (int j = i + 1; j < nums.size(); ++j) {
                if (j > i + 2
                    && nums[j] == nums[j - 1]
                    && nums[j - 1] == nums[j - 2]) { // 三元组元素b去重
                    continue;
                }
                int c = 0 - (nums[i] + nums[j]);
                if (uset.find(c) != uset.end()) {
                    result.push_back({nums[i], nums[j], c});
                    uset.erase(c);// 三元组元素c去重
                } else {
                    uset.insert(nums[j]);
                }
            }
        }
        return result;
    }
};

int main() {
    vector<int> nums{-1, 0, 1, 2, -1, -4};

    Solution solution;
    for (const auto& row: solution.threeSum(nums)) {
        for (auto ele: row) {
            cout << ele << " ";
        }
        cout << endl;
    }
}

使用双指针法:

#include <iostream>
#include <vector>

using namespace std;

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        vector<vector<int>> result;
        sort(nums.begin(), nums.end());
        // a = nums[i], b = nums[left], c = nums[right]
        for (int i = 0; i < nums.size(); ++i) {
            if (nums[i] > 0)
                return result; //也可以写 break;

            if (i > 0 && nums[i] == nums[i - 1])
                continue;

            int left = i + 1;
            int right = nums.size() - 1;
            while (right > left) {
                // 去重复逻辑如果放在这里,[0,0,0]的情况,可能直接导致 right<=left 了,从而漏掉了[0,0,0]这种三元组
                /*
                while (right > left && nums[right] == nums[right - 1]) right--;
                while (right > left && nums[left] == nums[left + 1]) left++;
                */
                if (nums[i] + nums[left] + nums[right] > 0) right--;
                else if (nums[i] + nums[left] + nums[right] < 0) left++;
                else {
                    result.push_back({nums[i], nums[left], nums[right]});
                    // 去重逻辑应该放在找到一个三元组之后,对b 和 c去重
                    while (right > left && nums[right] == nums[right - 1]) right--; //考虑[-3,1,1,1,1,2,2,2,2]边界情况
                    while (right > left && nums[left] == nums[left + 1]) left++;

                    // 找到答案时,双指针同时收缩
                    right--;
                    left++;
                }
            }

        }
        return result;
    }
};

int main() {
    vector<int> nums{-1, 0, 1, 2, -1, -4};

    Solution solution;
    for (const auto& row: solution.threeSum(nums)) {
        for (auto ele: row) {
            cout << ele << " ";
        }
        cout << endl;
    }
}

4、四数之和

#include <iostream>
#include <vector>

using namespace std;

class Solution {
public:
    vector<vector<int>> fourSum(vector<int>& nums, int target) {
        vector<vector<int>> result;
        sort(nums.begin(), nums.end());
        for (int k = 0; k < nums.size(); ++k) {
            // 剪枝处理
            if (nums[k] > target && nums[k] >= 0)
                break;

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

            for (int i = k + 1; i < nums.size(); ++i) {
                // 2级剪枝处理
                if (nums[k] + nums[i] > target && nums[i] >= 0) //这里nums[k]+nums[i]是一个整体
                    break;

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

                int left = i + 1;
                int right = nums.size() - 1;
                while (right > left) {
                    // nums[k] + nums[i] + nums[left] + nums[right] > target 会溢出
                    if ((long) nums[k] + nums[i] + nums[left] + nums[right] > target) {
                        right--;
                        // nums[k] + nums[i] + nums[left] + nums[right] < target 会溢出
                    } else if ((long) nums[k] + nums[i] + nums[left] + nums[right]  < target) {
                        left++;
                    } else {
                        result.push_back({nums[k], nums[i], nums[left], nums[right]});
                        // 对nums[left]和nums[right]去重
                        while (right > left && nums[right] == nums[right - 1]) right--;
                        while (right > left && nums[left] == nums[left + 1]) left++;

                        // 找到答案时,双指针同时收缩
                        right--;
                        left++;
                    }
                }

            }
        }
        return result;
    }
};

int main() {
    vector<int> nums{1, 0, -1, 0, -2, 2};
    int target = 0;

    Solution solution;
    for (const auto& row: solution.fourSum(nums, target)) {
        for (auto ele: row) {
            cout << ele << " ";
        }
        cout << endl;
    }
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
邓俊辉教授是计算机科学与技术领域著名的教育家和研究者。他在清华大学担任教授,并负责计算机算法与理论方向的研究和教学工作。邓俊辉教授是中国计算机学会副理事长、国际著名科技出版社Springer中国系列丛书主编、IEICE China Communications主编、Journal of Internet Technology编委、《数据结构与算法教程》作者等。 在邓俊辉教授的指导下,他办了多次Dijkstra算法训练,旨在培养学生对于算法学习的兴趣与能力。Dijkstra算法是一种用于图论中求解最短路径问题的经典算法,具有广泛的应用领域,如路由算法、网络规划和GPS导航系统等。在训练中,邓俊辉教授通过讲解算法的原理和思想,引导学生进行编程实践和案例分析,帮助他们深入理解Dijkstra算法的应用场景与实际解决问题的能力。 邓俊辉教授所组织的Dijkstra算法训练受到了广大学生的欢迎和积极参与。通过训练的学习,学生不仅可以掌握Dijkstra算法的具体实现过程,还能了解算法设计的思路和应用的局限性。在训练中,学生还可以与同学们进行交流和合作,共同解决实际问题,促进彼此的学术成长和人际交往能力的培养。 总之,邓俊辉的Dijkstra算法训练为学生提供了一个系统、全面学习算法知识的平台,帮助他们培养解决实际问题的能力和思维方式。通过这样的培训,学生不仅能在学术领域取得更好的成绩,还可以为将来的职业发展打下坚实的基础。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值