【面试HOT200】数组篇

news2024/11/22 21:29:30

系列综述:
💞目的:本系列是个人整理为了秋招面试coding部分的,整理期间苛求每个算法题目,平衡可读性代码性能(leetcode运行复杂度均打败80%以上)。
🥰来源:材料主要源于【CodeTopHot200】进行的,每个知识点的修正和深入主要参考各平台大佬的文章,其中也可能含有少量的个人实验自证,所有代码均优先参考最佳性能。
🤭结语:如果有帮到你的地方,就点个赞关注一下呗,谢谢🎈🎄🌷!!!
🌈【C++】秋招&实习面经汇总篇


文章目录

    • 基础题目
      • 二分查找
        • 基础知识
        • 相关例题
      • 快速排序(模糊划分)
        • 基础知识
        • 相关例题
      • 移除元素(快慢指针)
      • 两数之和(带哈希缓存的查找)
      • 三数之和(排序+三指针)
      • 四数相加II(unordered_map的使用)
      • 有序数组的平方(双端指针)
    • 参考博客


😊点此到文末惊喜↩︎

基础题目

二分查找

基础知识
  1. 适应场景:有序无重复的数组
    • 有序:一次比较即可确定需要查找的另一半,效率高的关键
    • 无重复:一旦有重复元素,使用二分查找法返回的元素下标可能不是唯一,需要进行左右的循环查找
    • 数组:可以进行随机存取
  2. 细节
    • 快速防溢出的除2:mid = L + ((R - L)>>1)
      • 防溢出:如果L 和 R太大,直接相加就有溢出的可能
      • 右移:等价于除法算法,但是效率高
    • 使用前闭后闭的二分区域查找,可以在查找target位置后再进行相同元素相连区域的定位操作。
  3. leetcode题目:704. 二分查找
    // *****************前闭后闭的基本二分查找,可以代替下一种*******************
    int search(vector<int>& nums, int target) {
    // 0. 健壮性检查
        if(nums.size() <= 0) return -1;
    // 1. 定义边界指针(指向遍历数组区域的边界位置)
        int left = 0;
        int right = nums.size() - 1; // 定义target在左闭右闭的区间里
    // 2. 基本算法步骤的循环    
        while (left <= right) { // 前闭后闭用<=
        	// 划分中间
            int mid = left + ((right - left)>>1);	// 防止溢出 等同于(left + right)/2
            if (target < nums[mid]) {				// 目标值在左区间
                right = mid - 1; 
            } else if (target > nums[mid]) {		// 目标值在右区间
                left = mid + 1; 
            } else {								// 找到目标值,即相等时
                return mid; 						// 数组中找到目标值,直接返回下标
            }
        }
    // 3. 添加进行左右边界的定位操作
    	// ...
        return left;// left为相等值未找到时应插入的位置,也可使用-1表示
    }
    
相关例题
  1. leetcode题目:35. 在排序数组中查找元素的第一个和最后一个位置
    • 先通过基本二分法查找目标元素出现的位置
    • 然后使用while(边界判断 && 值判断)获得target值的区间
    ···	// 基本二分查找
    // 寻找相似相邻区间的左右边界
    int l = mid;
    int r = mid;
    if(nums[mid] != target){
        return res;
    }else{
    	while (vec[left] == target && left >= 0) {
    		--left;
    	}
    	while (vec[right] == target && right <= vec.size() - 1) {
    		++right;
    	}
    }
    res[0]=l;
    res[1]=r;
    return res;
    }
    
    1. 搜索旋转排序数组
    • 整数数组 nums 按升序排列,但是可以进行循环移位,然后进行target的查找
    • 使用时间复杂度为 O(log n) 的算法
      在这里插入图片描述
    • 思路
      • nums[0] <= nums[mid](0 - mid不包含旋转)且nums[0] <= target <= nums[mid] 时 high 向前规约;
      • nums[mid] < nums[0](0 - mid包含旋转),target <= nums[mid] < nums[0] 时向前规约(target 在旋转位置到 mid 之间)
      • nums[mid] < nums[0],nums[mid] < nums[0] <= target 时向前规约(target 在 0 到旋转位置之间)
      • 其他情况向后规约
      • nums[mid] < nums[0],nums[0] > target,target > nums[mid] 三项均为真或者只有一项为真时向后规约
int search(vector<int>& nums, int target) {
    int lo = 0, hi = nums.size() - 1;
    while (lo < hi) {
        int mid = (lo + hi) / 2;
        if ((nums[0] > target) ^ (nums[0] > nums[mid]) ^ (target > nums[mid]))
            lo = mid + 1;
        else
            hi = mid;
    }
    return lo == hi && nums[lo] == target ? lo : -1;
}
  1. 正序数组查找第k小(二分查找)
    • 给定两个大小分别为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的 中位数
    • 算法的时间复杂度应该为 O(log (m+n))
class Solution {
public:
    int findKthElm(vector<int>& nums1,vector<int>& nums2,int k){
        assert(1<=k&&k<=nums1.size()+nums2.size());
        int le=max(0,int(k-nums2.size())),ri=min(k,int(nums1.size()));
        while(le<ri){
            int m=le+(ri-le)/2;
            if(nums2[k-m-1]>nums1[m]) le=m+1;//这为什么只写一个条件?!因为这是二分的排除条件,不是目标的符合条件,相当于排除条件,最后的结果才是符合条件的结果
            else ri=m;
        }//循环结束时的位置le即为所求位置,第k小即为max(nums1[le-1]),nums2[k-le-1]),但是由于le可以为0、k,所以
        //le-1或者k-le-1可能不存在所以下面单独判断下
        int nums1LeftMax=le==0?INT_MIN:nums1[le-1];
        int nums2LeftMax=le==k?INT_MIN:nums2[k-le-1];
        return max(nums1LeftMax,nums2LeftMax);
    }
    double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
        int n=nums1.size()+nums2.size();
        if(n&1){//两个数组长度和为奇数
            return findKthElm(nums1,nums2,(n>>1)+1);
        }
        else{//为偶数
            return (findKthElm(nums1,nums2,n>>1)+findKthElm(nums1,nums2,(n>>1)+1))/2.0;
        }
    }
};

快速排序(模糊划分)

基础知识
  1. 基本思想
    • 选择基准:在待排序列中,按照某种方式挑出一个元素,作为 “基准”(pivot)
    • 分割操作:以该基准在序列中的实际位置,把序列分成两个子序列。此时,在基准左边的元素都比该基准小,在基准右边的元素都比基准大
    • 递归地对两个序列进行快速排序,直到序列为空或者只有一个元素。
  2. 特点
    • 不产生有序子序列,但每次排序后会将基准元素放到最终位置上
    • 每次排序划分子区间越相近越能发挥快排优势
    • 每次可将无序线性表划分成小值区pivot大值区
  3. 算法
int partition(vector<int> &vec, int left, int right) {
    // 将第一个元素随机化,避免有序数组导致的划分失衡
    int idx = left + rand() % (right - left + 1);
    swap(vec[left], vec[idx]);
	// 初始化:划分元素的位置和值
    int pos = left;
    int pivot = vec[left];
    // 算法部分
    while (left < right) {
	    // 从后向前找 小于 基准元素的
	    while (vec[right] >= pivot && left < right) --right;
	    // 从前向后找 大于 基准元素的
	    while (vec[left] <= pivot && left < right) ++left;
        swap(vec[left], vec[right]);
    }
    swap(vec[left], vec[pos]);
    return left;	
}

void QuickSort(vector<int> &vec, int left, int right) {
  if (left > right) return ;
  int pivot = partition(vec, left, right);
  QuickSort(vec, left, pivot-1);
  QuickSort(vec, pivot+1, right);
}

在这里插入图片描述

相关例题
    1. 数组中的第K个最大元素
    • 题目:给定整数数组 nums 和整数 k,请返回数组中第 k 个最大的元素。
    • 思路
      • 快排划分:时间复杂度:O(N) 空间复杂度:O(1)
      • 堆求解:时间复杂度:O(Nlog⁡K) 空间复杂度:O(K)
// 快排划分 
int findKthLargst(vector<int>& nums, int k) {
    // 划分函数(key:从大到小)
    auto partition = [&](int left, int right)->int{
        // 随机化:避免划分失败
        int idx = left + rand() % (right-left+1);
        swap(nums[left], nums[idx]);
        // 划分元素的位置和值
        int pos = left;
        int pivot = nums[left];
        while (left < right) {
            while (nums[right] <= pivot && left < right) --right;
            while (nums[left] >= pivot && left < right) ++left;
            swap(nums[left], nums[right]);
        }
        // 划分转移
        swap(nums[left], nums[pos]);
        return left;
    };
    // 算法
    int left = 0;
    int right = nums.size()-1;
    // 找到正序数组中的第k大
    while (left <= right) {
        int mid = partition(left, right);
        if (k == mid+1) {
            return nums[mid];
        } else if (k > mid+1) {
            left = mid+1;
        } else {
            right = mid-1;
        }
    }
    return 0;
}
// 堆处理
int findKthLargest(vector<int>& nums, int k) {
    priority_queue<int> pq;
    for (auto &i : nums) {
        pq.push(i);
    }
    for (int i = 0; i < k-1; ++i) {
        pq.pop();
    }
    return pq.top();
}

移除元素(快慢指针)

  1. leetcode题目:27. 移除元素
    • 要求:使用快慢指针以O(n)的时间复杂度和O(1)的空间复杂度进行处理
    • 注意点
      • 快指针fast用于条件判断,慢指针slow用于位置保存
      • 尽量使用for循环避免结尾迭代条件的忘记
    int removeElement(vector<int>& nums, int val) {
        int slow = 0, fast = 0;     // 定义快慢指针
        for (; fast < nums.size(); ++fast) {
        	// 快指针进行判断判断
            if (nums[fast] != val) {
                nums[slow] = nums[fast];
                ++slow;
            }
        }
        nums.resize(slow);
        return slow;
    }
    

两数之和(带哈希缓存的查找)

  1. leetcode1. 两数之和
  2. 思路
    • 每次获取一个元素,先判断是否成功,如果不成功则将元素放入哈希缓存表中
    vector<int> twoSum(vector<int>& nums, int target) {
        vector<int> res;
        unordered_map<int, int> umap;
        for (int i = 0; i < nums.size(); ++i) {
            auto itr = umap.find(target-nums[i]);
            if (itr != umap.end()) {
                res.emplace_back(i);
                res.emplace_back(itr->second);
            }
            umap[nums[i]] = i;
        }
        return res;
    }
    

三数之和(排序+三指针)

  1. 15. 三数之和
    • 给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != j、i != k 且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请你返回所有和为 0 且不重复的三元组。
    • 答案中不可以包含重复的三元组。
  2. 思路
    • 固定一个指针进行问题的降维,然后另外两个指针进行区间的运算
      请添加图片描述
vector<vector<int>> threeSum(vector<int>& nums) {
    const int len = nums.size();
    vector<vector<int>> res;
    sort(nums.begin(), nums.end());
    // 健壮性检查 
    if (nums.size() < 3 || nums[0] > 0 || nums[nums.size()-1] < 0)
        return res;
    // 算法部分
    // 找出a + b + c = 0
    // a = nums[i], b = nums[left], c = nums[right]
    for (int i = 0; i < nums.size(); i++) {
        // 排序后若第一个元素大于零,则表示后面元素不可能凑成三元组
        if (nums[i] > 0) return res;
        // 正确去重方法:比较i和i+1会遗漏掉第一个元素作为首元素的情况
        if (i > 0 && nums[i] == nums[i - 1]) 
            continue;
        // 确定剩余两个元素的区间
        int left = i + 1;
        int right = nums.size() - 1;
        while (left < right) {
            if (nums[i] + nums[left] + nums[right] > 0) right--;
            else if (nums[i] + nums[left] + nums[right] < 0) left++;
            else {
                // 压入第一个,然后对后面的去重
                res.push_back(vector<int>{nums[i], nums[left], nums[right]});
                // 去重逻辑应该放在找到一个三元组之后,对b 和 c去重
                while (right > left && nums[right] == nums[right - 1]) right--;
                while (right > left && nums[left] == nums[left + 1]) left++;
                // 找到答案时,双指针同时收缩
                right--;
                left++;
            }
        }
    }
    return res;
}
  1. 注意点
    • 去重操作
      • if (nums[i] == nums[i + 1]) continue;会导致[-1,-1,2]情况的遗漏
      • if (i > 0 && nums[i] == nums[i - 1]) continue;优先判断左部分,不会影响右部分

四数相加II(unordered_map的使用)

  1. leetcode题目:四数相加
    • 记录去重常数级查找通过unordered_set解决
      在这里插入图片描述
    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]++;
            }
        }
        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) {
    			int val = -(c+d);
                if (umap.count(val) > 0) {
                    count += umap[val];
                }
            }
        }
        return count;
    }
    

有序数组的平方(双端指针)

  1. leetcode题目:977. 有序数组的平方
    在这里插入图片描述
  2. 思路:
    • 正常思路:从0开始向中间 + 辅助空间
    • 逆向思路:left和right两个指针分别从两端向中间进行夹逼
vector<int> sortedSquares(vector<int>& nums) {
    // 健壮性检查
    // 初始化
    const int len = nums.size();
    int left = 0;
    int right = len-1;
    vector<int> res(len);
    // 算法部分
    for (int index = len-1; left <= right; --index) {
        if (nums[left] * nums[left] > nums[right] *nums[right]) {
            res[index] = nums[left] * nums[left];
            ++left;
        } else {
            res[index] = nums[right] *nums[right];
            --right;
        }
    }
    return res;
}


少年,我观你骨骼清奇,颖悟绝伦,必成人中龙凤。
不如点赞·收藏·关注一波

🚩点此跳转到首行↩︎

参考博客

  1. 「代码随想录」
  2. codetop前200
  3. 力扣(LeetCode)
  4. 旋转数组——极简 Solution

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1564410.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

uniapp-打包app-图标配置

依次找到manifest->App图标配置&#xff0c;然后点击浏览&#xff0c;从本地文件夹中选择你们项目的logo&#xff0c;然后点击自动生成所有图标并替换&#xff0c;即可&#xff1a;

OpenHarmony实战:轻量级系统之安全子系统移植

安全子系统提供网络设备连接、认证鉴权等功能&#xff0c;依赖mbedtls实现硬件随机数以及联网功能。 由于每个厂商芯片硬件与实现硬件随机数的方式不同&#xff0c;需要适配硬件随机数接口。 移植指导 OpenHarmony提供了mbedtls的开源三方库&#xff0c;路径为“//third_par…

adobe stock会员开通付费付款订阅充值教程/adobe stock免费白嫖一个月

登录adobe stock的官网&#xff0c;点击你想要下载的视频&#xff0c;然后点击免费下载&#xff0c;我们点击免费试用按钮&#xff0c;可以看到非常贵&#xff0c;需要80美金一个月&#xff0c;用fomepay可以免费白嫖一个月 点击获取一张虚拟信用卡&#xff0c;就可以白嫖一个…

【Vscode】无法将“python,pip,node,npm等”识别为cmdlet...问题

问题出现场景 新换个电脑&#xff0c;然后重新安装了软件&#xff0c;又复现一次又一次“老生常谈”的问题。 解决方法 网络答案吧五花八门&#xff0c;我采取一个我的场景解决可行的方案&#xff0c; 首先我的场景是&#xff0c;环境变量&#xff0c;配置路径都是没有问题…

C#手术麻醉临床信息系统源码,自动生成麻醉记录单、各种手术麻醉相关医疗文书

麻醉临床信息系统&#xff0c;采用计算机和通信技术&#xff0c;实现监护仪、麻醉机、输液泵等设备输出数据的自动采集&#xff0c;采集的数据能够如实准确地反映患者生命体征参数的变化&#xff0c;并实现信息高度共享&#xff0c;根据采集结果&#xff0c;综合其他患者数据&a…

第五篇:3.4 用户归因和受众(User attribution and audience) - IAB/MRC及《增强现实广告效果测量指南1.0》

翻译计划 第一篇概述—IAB与MRC及《增强现实广告效果测量指南》之目录、适用范围及术语第二篇广告效果测量定义和其他矩阵之- 3.1 广告印象&#xff08;AD Impression&#xff09;第三篇广告效果测量定义和其他矩阵之- 3.2 可见性 &#xff08;Viewability&#xff09;第四篇广…

【Vue3源码学习】— CH2.7 Computed: Vue 3 计算属性深入解析

Computed: Vue 3 计算属性深入解析 1.计算属性的基本用法2. ComputedRefImpl 类深入解析JavaScript 中的 getter 函数 3. 计算属性的创建&#xff1a;computed 方法解析3.1 源码解析3.2 使用示例 4. 计算属性的工作原理5. 手动实现简化的计算属性6. 结语 在 Vue 3 的响应式系统…

go之web框架gin

介绍 Gin 是一个用 Go (Golang) 编写的 Web 框架。 它具有类似 martini 的 API&#xff0c;性能要好得多&#xff0c;多亏了 httprouter&#xff0c;速度提高了 40 倍。 如果您需要性能和良好的生产力&#xff0c;您一定会喜欢 Gin。 安装 go get -u github.com/gin-gonic/g…

XRDP登录ubuntu桌面闪退问题

修改 /etc/xrdp/startwm.sh unset DBUS_SESSION_BUS_ADDRESS unset XDG_RUNTIME_DIR . $HOME/.profile

【C语言】——指针七:数组和指针试题解析

【C语言】——指针七&#xff1a; 前言一、 s i z e o f sizeof sizeof 与 s t r l e n strlen strlen 的对比1.1、 s i z e o f sizeof sizeof1.2、 s t r l e n strlen strlen1.3、 s i z e o f sizeof sizeof 和 s t r l e n strlen strlen 对比 二、数组和指针笔试题解析…

C++之优化Linux内核结构体用智能指针std::unique_ptr与std::make_unique分配内存总结(二百六十五)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…

自贡市第一人民医院:超融合与 SKS 承载 HIS 等核心业务应用,加速国产化与云原生转型

自贡市第一人民医院始建于 1908 年&#xff0c;现已发展成为集医疗、科研、教学、预防、公共卫生应急处置为一体的三级甲等综合公立医院。医院建有“全国综合医院中医药工作示范单位”等 8 个国家级基地&#xff0c;建成高级卒中中心、胸痛中心等 6 个国家级中心。医院日门诊量…

Linux (Ubuntu)- mysql8 部署

1.基本部署 01》》先查看OS类型&#xff0c;如果是Ubuntu在往下边看 rootspray:/etc/mysql/mysql.conf.d# lsb_release -a LSB Version: core-11.1.0ubuntu2-noarch:security-11.1.0ubuntu2-noarch Distributor ID: Ubuntu Description: Ubuntu 20.04.6 LTS Release: …

Movavi Video Converter 2022 for Mac/Win:卓越的视频音频文件转换器

在数字化时代&#xff0c;视频和音频文件已成为我们日常生活和工作中不可或缺的一部分。无论是制作精美的家庭影片&#xff0c;还是编辑专业的商业视频&#xff0c;一款高效、便捷的视频音频文件转换器无疑是您的得力助手。而Movavi Video Converter 2022&#xff0c;就是这样一…

GPT 模型解析:ChatGPT 如何在语言处理领域引领潮流?

人工智能时代来临 我们正处于AI的iPhone时刻。——黄仁勋&#xff08;英伟达CEO&#xff09; ChatGPT 好得有点可怕了&#xff0c;我们距离危险的强人工智能不远了。——马斯克&#xff08;Tesla/SpaceX/Twitter CEO&#xff09; 以上的内容说明我们现在正处于一个技术大翻牌的…

测斜仪在边坡安全监测中的重要作用

边坡作为土木工程和地质工程领域中常见的结构形式&#xff0c;其稳定性直接关系到工程安全以及人民生命财产的安全。因此&#xff0c;对边坡进行精确、及时的监测是至关重要的。在众多边坡监测仪器中&#xff0c;测斜仪以其独特的优势在边坡安全监测中发挥着重要的作用。 测斜仪…

(24年4月2日更新)Linux安装chrome及chromedriver(Ubuntu20.0416.04)

一、安装Chrome 1&#xff09;先执行命令下载chrome&#xff1a; wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb2&#xff09;安装chrome sudo dpkg -i google-chrome-stable_current_amd64.deb踩坑&#xff1a;这里会提示如下报错&…

C刊级 | Matlab实现GWO-BiTCN-BiGRU-Attention灰狼算法优化双向时间卷积双向门控循环单元融合注意力机制多变量回归预测

C刊级 | Matlab实现GWO-BiTCN-BiGRU-Attention灰狼算法优化双向时间卷积双向门控循环单元融合注意力机制多变量回归预测 目录 C刊级 | Matlab实现GWO-BiTCN-BiGRU-Attention灰狼算法优化双向时间卷积双向门控循环单元融合注意力机制多变量回归预测效果一览基本介绍程序设计参考…

大数据实验一,Hadoop安装及使用

目录 一&#xff0e;实验内容 二&#xff0e;实验目的 三&#xff0e;实验过程截图及说明 1、安装SSH&#xff0c;并配置SSH无密码登录 2、配置java环境 3.Hadoop的安装与配置 4、修改四个配置文件&#xff1a; 5、格式化HDFS的NameNode&#xff1a; 6、启动Hadoop 7、…

springcloud基本使用五(Gateway服务网关)

为什么使用网关&#xff1f; 权限控制&#xff1a;网关作为微服务入口&#xff0c;需要校验用户是是否有请求资格&#xff0c;如果没有则进行拦截。 路由和负载均衡&#xff1a;一切请求都必须先经过gateway&#xff0c;但网关不处理业务&#xff0c;而是根据某种规则&#xff…