日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【绝知此事要躬行】线性表之数组OJ

發(fā)布時(shí)間:2023/12/20 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【绝知此事要躬行】线性表之数组OJ 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

[線性表–數(shù)組OJ] (C/C++實(shí)現(xiàn))

學(xué)而時(shí)習(xí)之,不亦說乎

哈嘍又見面啦😁,沿著上篇我們討論的線性表中的順序表,這篇博客,我們講將介紹一些數(shù)組OJ題目,學(xué)習(xí)一些關(guān)于數(shù)組的操作(騷操作)。

ps: 本節(jié)所有代碼實(shí)現(xiàn)都是leetcode上的接口型

文章目錄

    • [線性表--數(shù)組OJ] (C/C++實(shí)現(xiàn))
    • @[toc]
      • 1.[leetcode 17.04. 消失的數(shù)字](https://leetcode-cn.com/problems/missing-number-lcci/)
        • **解法一**:掃一遍數(shù)組求出實(shí)際總和`sum1`,再利用==**等差數(shù)列求和公式**==,求出期望的總和`sum2`。
        • **解法二**(==位運(yùn)算==):
      • 2.[ 數(shù)組中數(shù)字出現(xiàn)的次數(shù)(leetcode)](https://leetcode-cn.com/problems/shu-zu-zhong-shu-zi-chu-xian-de-ci-shu-lcof/)
      • 3.[ 二分查找(leetcode)](https://leetcode-cn.com/problems/binary-search/)
        • **3-1.target 定義在[left,right] (==左右都是閉區(qū)間的寫法==)**
        • **3.2. target定義在[left,right)的開區(qū)間中(==左開右閉區(qū)的寫法==)**
      • 4.[移除元素(leetcode)](https://leetcode-cn.com/problems/remove-element/)
        • **解法一:暴力循環(huán),移動覆蓋** O(N^2)
        • **解法二:雙指針 **O(N)
          • 快慢指針
          • 左右指針
      • 5.[ 刪除有序數(shù)組中的重復(fù)項(xiàng)(leetcode)](https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array/)
      • 6.[合并兩個(gè)有序數(shù)組(leetcode)](https://leetcode-cn.com/problems/merge-sorted-array/)
      • 7.[輪轉(zhuǎn)數(shù)組(leetcode)](https://leetcode-cn.com/problems/rotate-array/)
        • 解法一(原數(shù)組與輪轉(zhuǎn)數(shù)組間的下標(biāo)關(guān)系):
        • 解法二:三次逆置(個(gè)人覺得這個(gè)方法超秀😍😍)

1.leetcode 17.04. 消失的數(shù)字

題目描述:

數(shù)組nums包含從0到n的所有整數(shù),但其中缺了一個(gè)。請編寫代碼找出那個(gè)缺失的整數(shù)。你有辦法在O(n)時(shí)間內(nèi)完成嗎?

示例:nums=[3,0,4,5,7,1,2],n=7 輸出:6

解法一:掃一遍數(shù)組求出實(shí)際總和sum1,再利用==等差數(shù)列求和公式==,求出期望的總和sum2。

sum2-sum1即為缺失的數(shù)字。

代碼實(shí)現(xiàn):

class Solution { public:int missingNumber(vector<int>& nums) {int sum1=0;int sum2=(nums.size()+1)*nums.size()/2;for(int i=0;i<nums.size();i++)sum1+=nums[i];return sum2-sum1;} };

解法二(位運(yùn)算):

首先,我們先來介紹一下異或(^)運(yùn)算

aba^b
000
011
101
110

相同為0,不同為1

例如:a=12,b=9,a的二級制表示:1100,b的二進(jìn)制表示:1001

a^b為a與b按每一個(gè)每一個(gè)比特位異或,結(jié)果為:0101 ,即12^9=5

易知曉a ^ b=b ^ a,即異或操作滿足交換律

可是這有什么用咧???👀👀

由定義我們可以得到一些性質(zhì):

  • 0 ^ a = a

  • a ^ a = 0

    由交換律和性質(zhì)1,2 我們不難證明類似這樣的式子:a ^ b ^ c ^ b ^ c =a

  • 借助位運(yùn)算我們可以通過如下操作把這道題解決:

  • 把nums數(shù)組中的所有元素異或一遍的結(jié)果存在ret中
  • 把ret再同1到n的所有數(shù)異或一遍,ret即為缺失的數(shù)字
  • 因?yàn)?#xff0c;經(jīng)歷了上述操作,1-n出現(xiàn)的數(shù)字都異或了兩遍,缺失的數(shù)字僅異或了一遍

    代碼實(shí)現(xiàn):

    class Solution { public:int missingNumber(vector<int>& nums) {int ret=0;for(int i=0;i<nums.size();i++)ret^=nums[i];for(int i=1;i<=nums.size();i++)ret^=i;return ret;} };

    2. 數(shù)組中數(shù)字出現(xiàn)的次數(shù)(leetcode)

    ? 接著上一題異或運(yùn)算的腳步,我們來看一下這道題,對異或運(yùn)算的進(jìn)一步運(yùn)用。

    題目描述

    一個(gè)整型數(shù)組 nums 里除兩個(gè)數(shù)字之外,其他數(shù)字都出現(xiàn)了兩次。請寫程序找出這兩個(gè)只出現(xiàn)一次的數(shù)字。要求時(shí)間復(fù)雜度是O(n),空間復(fù)雜度是O(1)。

    示例: nums=[1,1,2,3,3,4,5,5] 輸出:[2,4]

    如果順著上題我們走過的路徑,我們可能的第一個(gè)想法就是,掃一遍數(shù)組全部異或一下

    但是如果記兩個(gè)只出現(xiàn)一次的數(shù)字分別為a和b ,最后我們得到的是a^b,根據(jù)這個(gè)結(jié)果我們并不能把a(bǔ)和b分出來。此時(shí)我們就遇上難題了。

    讓我們看看現(xiàn)在有些什么可以利用的?

    a^b的值,這個(gè)值雖然不能直接給我們a和b具體是多少,但是可以提供給我們一些關(guān)于a和b的性質(zhì)

    通過a^b我們可以獲取a和b二進(jìn)制表示中不同的那個(gè)位(即a ^ b的二進(jìn)制表示中為1的那個(gè)位)

    我們通過一個(gè)flag加上左移操作便可以找到那個(gè)不同的位

    這樣我們便可以把數(shù)字分為兩組,進(jìn)行==分組異或==

    不難證明:

  • 只出現(xiàn)一次的兩個(gè)數(shù)一定分到不同的組
  • 兩次出現(xiàn)的數(shù)字一定分到相同的組
  • 代碼實(shí)現(xiàn)

    class Solution { public:vector<int> singleNumbers(vector<int>& nums) {int val=0,flag=1;for(int i=0;i<nums.size();i++)val^=nums[i];while((val&flag)==0){flag<<=1;}int a=0,b=0;for(int i=0;i<nums.size();i++){if(nums[i]&flag)a^=nums[i];elseb^=nums[i];}return {a,b};} };

    3. 二分查找(leetcode)

    題目描述:

    給定一個(gè) n 個(gè)元素有序的(升序)整型數(shù)組 nums 和一個(gè)目標(biāo)值target ,寫一個(gè)函數(shù)搜索 nums 中的 target,如果目標(biāo)值存在返回下標(biāo),否則返回 -1。

    3-1.target 定義在[left,right] (左右都是閉區(qū)間的寫法)

    class Solution { public:int search(vector<int>& nums, int target) {int left=0,right=nums.size()-1;while(left<=right){int mid=(left+right)/2;if(nums[mid]>target)right=mid-1;else{if(nums[mid]<target)left=mid+1;elsereturn mid;}}return -1;} }; int middle = left + ((right - left) / 2);// 防止溢出 等同于(left + right)/2

    3.2. target定義在[left,right)的開區(qū)間中(左開右閉區(qū)的寫法)

    class Solution { public:int search(vector<int>& nums, int target) {int left=0,right=nums.size();//開區(qū)間while(left<right)//等于的情況沒有意義{int mid=(left+right)/2;//可寫成防止溢出的寫法if(nums[mid]>target)//左區(qū)間right=mid;else{if(nums[mid]<target)left=mid+1;elsereturn mid;}}return -1;} };

    解釋:

    ①.while循環(huán)中判斷條件等于就沒有意義

    ②.target落在左區(qū)間內(nèi)mid-1可能取到而mid不能取到,所以right=mid


    4.移除元素(leetcode)

    題目描述:

    給你一個(gè)數(shù)組 nums 和一個(gè)值 val,你需要 原地 移除所有數(shù)值等于 val 的元素,并返回移除后數(shù)組的新長度。

    不要使用額外的數(shù)組空間,你必須僅使用 O(1) 額外空間并 原地 修改輸入數(shù)組。

    元素的順序可以改變。你不需要考慮數(shù)組中超出新長度后面的元素。

    解法一:暴力循環(huán),移動覆蓋 O(N^2)

    代碼實(shí)現(xiàn):

    class Solution { public:int removeElement(vector<int>& nums, int val) {int sz=nums.size();for(int i=0;i<sz;i++){if(val==nums[i]){for(int j=i;j<sz-1;j++)nums[j]=nums[j+1];i--;sz--;}}return sz;} };

    !!!注意!!!

    第11行的 i - -回退一步非常重要

    因?yàn)槲覀儧]法判斷用來覆蓋的前一個(gè)元素的值是否等于val

    這個(gè)是用來應(yīng)對val連續(xù)出現(xiàn)的情況

    **解法二:雙指針 **O(N)

    這里我們介紹兩種雙指針實(shí)現(xiàn)方式來完成這一題

  • 快慢指針

    思路:

  • 我們開始時(shí)使得slow與fast都為0
  • 如果nums[fast] != val 和那么fast和slow一起走,如果fast指的值等于val,fast走而slow不走
  • 每次fast和slow實(shí)現(xiàn)一起走的時(shí)候,即為把fast指的的值給slow
  • 這樣我們可以證明:fast走完一遍時(shí),0~slow所有的值都不等于val

    class Solution { public:int removeElement(vector<int>& nums, int val) {int slow=0;for(int fast=0;fast<nums.size();fast++)if(nums[fast]!=val)nums[slow++]=nums[fast];return slow;} };
  • 左右指針

    思路:

  • left指頭,right指尾

  • 每次當(dāng)left指的值等于val,left指向的值是必要?jiǎng)h除的,此時(shí)我們把right指的值給left,更新right(用尾的元素覆蓋這個(gè)必要?jiǎng)h的元素,雖然不能判定尾這個(gè)元素是否等于val)

  • left指的值不等于val,left往前走即可

    注意循環(huán)的判定條件要取到等(得判定所有的元素)

  • 可以發(fā)現(xiàn):nums中每個(gè)元素都判定過,且0~left的所有元素都不等于val

    代碼實(shí)現(xiàn):

    class Solution { public:int removeElement(vector<int>& nums, int val) {int left=0,right=nums.size()-1;while(left<=right){if(val==nums[left]){nums[left]=nums[right];right--;}elseleft++;}return left;} };

    5. 刪除有序數(shù)組中的重復(fù)項(xiàng)(leetcode)

    題目描述

    給你一個(gè) 升序排列 的數(shù)組 nums ,請你原地刪除重復(fù)出現(xiàn)的元素,使每個(gè)元素 只出現(xiàn)一次 ,返回刪除后數(shù)組的新長度。元素的 相對順序 應(yīng)該保持 一致 。

    思路:

  • 升序排列:說明數(shù)組中重復(fù)出現(xiàn)的元素一定是連續(xù)的,不可能間斷

  • 我們用k表示刪除元素(重復(fù)元素)的個(gè)數(shù),val記錄==上一層循環(huán)的nums[i]==

  • 在當(dāng)前循環(huán)層中如果val==nums[i],說明該層循環(huán)nums[i]為重復(fù)元素,根據(jù)我們在2中給的定義,k需要加1,val可以更新(但沒必要)

  • 當(dāng)前循環(huán)層中的值不等于val,說明這個(gè)不是重復(fù)元素,i-k位置上的元素即為在[0,i)這個(gè)區(qū)間中第一個(gè)出現(xiàn)重復(fù)的元素(1中連續(xù)性結(jié)合2中定義得出)

    示意圖

  • 掃完一遍后,nums.size()-k即為剩下元素的個(gè)數(shù),且滿足[0,nums.size()-k]區(qū)間上·不存在重復(fù)元素。

  • 代碼實(shí)現(xiàn):

    class Solution { public:int removeDuplicates(vector<int>& nums) {int k=0,val=nums[0];for(int i=1;i<nums.size();i++){if(val==nums[i]){k++;}else{val=nums[i];nums[i-k]=nums[i];}}return nums.size()-k;} };

    6.合并兩個(gè)有序數(shù)組(leetcode)

    題目描述:

    給你兩個(gè)按 非遞減順序 排列的整數(shù)數(shù)組 nums1 和 nums2,另有兩個(gè)整數(shù)m和 n ,分別表示 nums1 和 nums2 中的元素?cái)?shù)目。

    請你 合并 nums2 到 nums1 中,使合并后的數(shù)組同樣按 非遞減順序 排列。

    思路:

    因?yàn)閮蓚€(gè)數(shù)組都排好序,只需同時(shí)掃兩個(gè)數(shù)組,每次把小的放到ans數(shù)組中

    若m==n掃完一遍后,兩數(shù)組按序插入到ans中

    如果m != n最后只需把長的數(shù)組后面的元素統(tǒng)統(tǒng)放到ans中即可。

    (這也是我們后續(xù)要寫的==歸并排序==的歸并操作)

    代碼實(shí)現(xiàn):

    class Solution { public:void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {vector<int> ans;int i=0,j=0;while(i<m&&j<n){if(nums1[i]<nums2[j])ans.push_back(nums1[i++]);elseans.push_back(nums2[j++]);}while(i<m)ans.push_back(nums1[i++]);while(j<n)ans.push_back(nums2[j++]);nums1=ans;} };

    7.輪轉(zhuǎn)數(shù)組(leetcode)

    題目描述:

    給你一個(gè)數(shù)組,將數(shù)組中的元素向右輪轉(zhuǎn) k 個(gè)位置,其中 k 是非負(fù)數(shù)。

    示例:

    輸入: nums = [1,2,3,4,5,6,7], k = 3
    輸出: [5,6,7,1,2,3,4]
    解釋:
    向右輪轉(zhuǎn) 1 步: [7,1,2,3,4,5,6]
    向右輪轉(zhuǎn) 2 步: [6,7,1,2,3,4,5]
    向右輪轉(zhuǎn) 3 步: [5,6,7,1,2,3,4]

    解法一(原數(shù)組與輪轉(zhuǎn)數(shù)組間的下標(biāo)關(guān)系):

    如果原數(shù)組為nums1[i] ,輪轉(zhuǎn)后數(shù)組為nums2

    可知:nums2[ i ] = nums1[ (i+k) % nums1.size() ]

    代碼實(shí)現(xiàn):

    class Solution { public:void rotate(vector<int>& nums, int k) {int size=nums.size();vector<int> ans(size);for(int i=0;i<size;i++)ans[(i+k)%size]=nums[i];nums=ans;} };

    解法二:三次逆置(個(gè)人覺得這個(gè)方法超秀😍😍)

    基本操作:

    reverse函數(shù) 把1,2,3,4,5完全逆置為5,4,3,2,1(雙指針實(shí)現(xiàn))

    此時(shí)只需要(記原數(shù)組長度為size):

  • 把[0,size - k % size -1 ]逆置
  • 把[size - k % size, size-1 ]逆置
  • 最后把nums整體再逆置一遍
  • 注意k要對size取模(輪轉(zhuǎn)size次相當(dāng)于轉(zhuǎn)回來了)

    代碼實(shí)現(xiàn):

    class Solution { public:void reverse(vector<int>& nums, int begin, int end){int i=begin,j=end;while(i<j){int tmp=nums[i];nums[i]=nums[j];nums[j]=tmp;i++,j--;}}void rotate(vector<int>& nums, int k) {int size=nums.size();reverse(nums,0,size-k%size-1);reverse(nums,size-k%size,size-1);reverse(nums,0,size-1);} };

    ??本篇博客關(guān)于數(shù)組OJ的內(nèi)容就到這了

    總結(jié)一下:我們了解到了位運(yùn)算,二分查找,數(shù)組的插入刪除等操作的運(yùn)用,雙指針。

    希望大家看完能獲得一些啟發(fā),有所收獲

    本章節(jié)內(nèi)容所有源碼都會上傳到我的gitee代碼倉庫中,如有需要可前往下載,gitee鏈接:數(shù)據(jù)結(jié)構(gòu)

    受作者水平所限,如果博客內(nèi)容有什么紕漏錯(cuò)誤,歡迎大家批評指正

    如果大家對這些題目有什么好的方法思路,也歡迎大家來和我交流😉

    后續(xù)更新鏈表oj(難度up up)和《棧與隊(duì)列》

    我們下節(jié)見😊😊

    總結(jié)

    以上是生活随笔為你收集整理的【绝知此事要躬行】线性表之数组OJ的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。