三周攻克数据结构第一天

329 阅读2分钟

这是我参与11月更文挑战的第1天,活动详情查看:2021最后一次更文挑战

  三周攻克数据结构,是LeetCode上的一个学习活动,每天三道题,用三周时间重温典型数据结构。

只出现一次的数字

  1. 不考虑时间复杂度与空间复杂度的解法

    • 使用集合存储数字,如果集合中有该数字则删除,如果集合中没有该数字则添加。最后集合剩下的数字就是只出现一次的数字。
    • 使用哈希表存储数字和数字出现的次数,最后遍历哈希表得到只出现一次的数字。
    • 使用集合存储出现过的数字,计算数组的和以及集合的和,两个和的差值就是只出现一次的数字。
  2. 使用位运算

    异或运算

    a ^ 0 = a;

    a ^ a = 0;

    a ^ a ^ b = b;

  通过将数组的所有数字进行异或运算,最后结果就是只出现一次的数字,时间复杂度为O(n),空间复杂度为O(1)

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

多数元素

  使用哈希表,存储每个元素以及出现的次数。对于哈希映射中的每个键值对,键表示一个元素,值表示该元素出现的次数。为了省去最后遍历哈希表的时间,可以在将元素加入哈希表时维护最多次出现的值。

class Solution {
public:
    int majorityElement(vector<int>& nums) {
        unordered_map<int, int> counts;
        int majority = 0, cnt = 0;
        for (int num: nums) {
            ++counts[num];
            if (counts[num] > cnt) { //记录当前最多次出现的元素及出现的次数
                majority = num;
                cnt = counts[num];
            }
        }
        return majority;
    }
};

三数之和

  使用排序+双指针的方法,降低时间复杂度。

  • 首先对数组进行排序,排序后固定一个数 nums[i],再使用左右指针指向 nums[i]后面的两端,数字分别为 nums[L] 和 nums[R],计算三个数的和 sum 判断是否满足为 00,满足则添加进结果集
  • 如果 nums[i]大于 00,则三数之和必然无法等于 00,结束循环
  • 如果 nums[i] == nums[i-1],则说明该数字重复,会导致结果重复,所以应该跳过
  • 当 sum == 0 时,nums[L] == nums[L+1] 则会导致结果重复,应该跳过,L++
  • 当 sum == 0 时,nums[R] == nums[R-1] 则会导致结果重复,应该跳过,R--
class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        int n = nums.size();
        sort(nums.begin(), nums.end());
        vector<vector<int>> ans;
        for (int first = 0; first < n; ++first) {
            if (first > 0 && nums[first] == nums[first - 1]) {
                continue;
            }
            int third = n - 1;
            int target = -nums[first];
            for (int second = first + 1; second < n; ++second) {
                if (second > first + 1 && nums[second] == nums[second - 1]) {
                    continue;
                }
                while (second < third && nums[second] + nums[third] > target) {
                    --third;
                }
                if (second == third) {
                    break;
                }
                if (nums[second] + nums[third] == target) {
                    ans.push_back({nums[first], nums[second], nums[third]});
                }
            }
        }
        return ans;
    }
};