数据结构重点知识整理

1.数组/顺序表

概念:用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储

常见笔试面试题

1.1旋转数组

189. 轮转数组

1.1.1 模拟旋转-时间复杂度O(n),空间复杂度O(n)
cpp 复制代码
    void rotate(vector<int>& nums, int k) {
        int n = nums.size();
        vector<int> ret(n);
        for (int i = 0; i < n; i++) {
            ret[(i + k) % n] = nums[i];
        }
        nums = ret;
    }
1.1.2 数组翻转--时间复杂度O(n),空间复杂度O(1)
cpp 复制代码
    void reserve(vector<int>& nums, int begin, int end) {
        while (begin < end) {
            swap(nums[begin], nums[end]);
            begin += 1;
            end -= 1;
        }
    }
    void rotate(vector<int>& nums, int k) {
        k %= nums.size();
        reserve(nums, 0, nums.size() - 1);
        reserve(nums, 0, k - 1);
        reserve(nums, k, nums.size() - 1);
    }
1.1.3 删除排序数组中的重复项

26. 删除有序数组中的重复项

bash 复制代码
 int removeDuplicates(vector<int>& nums) {
        int n = nums.size();
        int slow = 1, fast = 1;
        if (n == 0)
            return 0;
        while (fast < n) {
            if(nums[fast]!=nums[fast-1]){
                nums[slow++]=nums[fast];
            }
            fast++;
        }
        return slow;
    }
1.1.4 数组形式的整形加法

方法一:逐位相加

思路

让我们逐位将数字加在一起。例如计算 123+912,我们从低位到高位依次计算 3+2、2+1 和 1+9。任何时候,若加法的结果大于等于 10,把进位的 1 加入到下一位的计算中,所以最终结果为 1035。

cpp 复制代码
    vector<int> addToArrayForm(vector<int>& num, int k) {
        int flag = 0;//进位标志位
        int index = num.size() - 1;//索引位数
        while (index >= 0) {
            int a = k % 10;
            k /= 10;
            num[index] = num[index] + a + flag;
            flag = num[index] / 10;
            num[index] = num[index] % 10;
            index--;
        }
        if (flag != 0) {
            k += flag;
        }
        while (k != 0) {
            int a = k % 10;
            k /= 10;
            num.insert(num.begin(), a);
        }
        return num;
    }

1.1.5 乘积最大子数组

152. 乘积最大子数组

cpp 复制代码
    int maxProduct(vector<int>& nums) {
        int n = nums.size();
        vector<int> f(n);
        vector<int> g(n);
        f[0] = g[0] = nums[0];
        int ans = 0;
        for (int i = 1; i < n; i++) {
            f[i] = max(g[i - 1] * nums[i], max(nums[i], f[i - 1] * nums[i]));
            g[i] = min(g[i - 1] * nums[i], min(nums[i], f[i - 1] * nums[i]));
            ans = max(f[i], ans);
        }
        return ans;
    }
1.1.5 众数

169. 多数元素

1.利用哈希表统计次数与n/2进行比较

cpp 复制代码
    int majorityElement(vector<int>& nums) {
        unordered_map<int, int> counts;
        int len = nums.size() / 2;
        for (int num : nums) {
            counts[num]++;
            if (counts[num] > len) {
                return num;
            }
        }
        return 0;
    }

时间复杂度O(n),空间复杂度O(n)

2. 排序

由于众数是大于2/n的,说明排完序后,在nums[n/2]的位置就是众数的值

cpp 复制代码
    int majorityElement(vector<int>& nums) {
        sort(nums.begin(), nums.end());
        return nums[nums.size() / 2];
    }

3. 利用随机值

随机一个值,在通过计数器比较,这个数很有可能就是众数,但有可能一直跳不出循环,但这是最坏的情况

cpp 复制代码
   int majorityElement(vector<int>& nums) {
       while (true) {
            int ret = nums[rand() % nums.size()];
            int count = 0;
            for (int num : nums)
                if (num == ret)
                    ++count;
            if (count > nums.size() / 2)
                return ret;
        }
        return -1;
    }

时间复杂度:理论上最坏情况下的时间复杂度为 O(∞),因为如果我们的运气很差,这个算法会一直找不到众数,随机挑选无穷多次,所以最坏时间复杂度是没有上限的。然而,运行的期望时间是线性的。为了更简单地分析,先说服你自己:由于众数占据 超过 数组一半的位置,期望的随机次数会小于众数占据数组恰好一半的情况。因此,我们可以计算随机的期望次数(下标为 prob 为原问题,mod 为众数恰好占据数组一半数目的问题):

计算方法为:当众数恰好占据数组的一半时,第一次随机我们有1/2的概率找到众数,如果没有找到,则第二次随机时,包含上一次我们有1/4的概率找到众数,以此类推。因此期望的次数为i*1/(2^i)的和,可以计算出这个和为 2,说明期望的随机次数是常数。每一次随机后,我们需要 O(n) 的时间判断这个数是否为众数,因此期望的时间复杂度为 O(n)。

1.1.6 分治
cpp 复制代码
    int count_in_range(vector<int>& nums, int target, int left, int right) {
        int count = 0;
        for (int i = left; i <= right; i++) {
            if (nums[i] == target)
                count++;
        }
        return count;
    }

    int majority_element_rec(vector<int>& nums, int left, int right) {
        if (left == right)
            return nums[left];
        int mid = (right - left) / 2 + left;
        int left_majority = majority_element_rec(nums, left, mid);
        int right_majority = majority_element_rec(nums, mid + 1, right);
        if (count_in_range(nums, left_majority, left, right) >
            ((right - left + 1) / 2))
            return left_majority;
        if (count_in_range(nums, right_majority, left, right) >
            ((right - left + 1) / 2))
            return right_majority;
        return -1;
    }

    int majorityElement(vector<int>& nums) {
        return majority_element_rec(nums, 0, nums.size() - 1);
    }

时间复杂度O(nlogn) 空间复杂度O(logn)

Boyer-Moore 投票算法

如果我们把众数记为 +1,把其他数记为 −1,将它们全部加起来,显然和大于0,从结果本身我们可以看出众数比其他数多。

cpp 复制代码
    int majorityElement(vector<int>& nums) {
        int candidate = -1;
        int count = 0;
        for (int num : nums) {
            if (num == candidate)
                count++;
            else if (--count < 0) {
                candidate = num;
                count = 1;
            }
        }
        return candidate;
    }
1.1.7 存在重复元素

217. 存在重复元素

这题一眼看上去就是遍历数组,判断数量是否>1,但结果很不尽人意,**nums的值可能为负数,**这时候我们就像想到了哈希表,哈希表中我们使用set还是map呢,都可以的,map的话则与前文一样,这里我选用set,**set在插入时会返回一个pair<iterator,bool>,**迭代器为哈希表中与这个值相同的迭代器,bool则是是否插入成功(是否相同),我们就可以利用这个条件

  • -109 <= nums[i] <= 109
cpp 复制代码
 int hashi[10010];
    bool containsDuplicate(vector<int>& nums) {
        for (int num : nums) {
            hashi[num]++;
            if (hashi[num] > 1) {
                return true;
            }
        }
        return false;
    }

判断条件我们可以计算最后的哈希表的长度是否一样,也可以给nums排序,进行便利,也是很好的,解题方法是多样的

1.1.8 探索二维数组

240. 搜索二维矩阵 II

cpp 复制代码
  bool searchMatrix(vector<vector<int>>& matrix, int target) {
        int n = matrix.size(), m = matrix[0].size();
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                if (i < n && j < m && matrix[i][j] == target)
                    return true;
                if (i < n && j < m && matrix[i][j] > target) {
                    j = -1;
                    i++;
                }
            }
        }
        return false;
    }

不定时更新中......

相关推荐
x_xbx1 小时前
LeetCode:70. 爬楼梯
算法·leetcode·职场和发展
weixin_307779131 小时前
提升 LLM 输出鲁棒性:使用 json_repair 智能修复非标准 JSON
开发语言·人工智能·算法·json·软件工程
TracyCoder1231 小时前
LeetCode Hot100(64/100)——70. 爬楼梯
算法·leetcode·职场和发展
重庆兔巴哥1 小时前
如何使用Dev-C++的Windows API进行GUI开发?
开发语言·c++·windows
㓗冽1 小时前
矩形面积交-进阶题7
算法
y = xⁿ1 小时前
【LeetCodehot100】T24:两两交换链表中的节点 T25:K个一组翻转链表
java·网络·数据结构·算法·链表
nananaij1 小时前
【LeetCode-04 数组异或操作 python解法】
python·算法·leetcode
少许极端2 小时前
算法奇妙屋(三十一)-递归、回溯与剪枝的综合问题 4
算法·剪枝·回溯·递归
mjhcsp2 小时前
C++随机调整(Random Adjustment):优化算法的核心随机策略
java·c++·算法