每天一道算法題(第三十二期)

2021-01-14 驚天碼盜

如果避免失敗成為你做事的動機,你就會陷入消極怠工的壯態。

前言

這幾天比較忙,所以晚了一點總結。這周的題是隨機抽取,沒有特定的主題。算法題解沒有特定的思路,可能一人有一個思路,例如有的題既可以使用動規,又可以使用分治。殊途同歸,算法的目的就是提升效率。

連續數列

給定一個整數數組,找出總和最大的連續數列,並返回總和。

示例:

輸入: [-2,1,-3,4,-1,2,1,-5,4]
輸出: 6
解釋: 連續子數組 [4,-1,2,1] 的和最大,為 6。

進階:

如果你已經實現複雜度為 O(n) 的解法,嘗試使用更為精妙的分治法求解。

用數組的每一個元素和其他元素組成一個子序列。再判斷每個子序列和的大小。

var maxSubArray = function (nums) {

  let arr = nums[0]

  for (let i = 0; i < nums.length; i++) {

      let sum = nums[i]

      arr = Math.max(nums[i],arr)

      for (let j = i + 1; j < nums.length; j++) {

          sum += nums[j]

          if (arr < sum) {

              arr = sum

          }

      }

  }

  return arr

};

最大子序和是動規的經典例題,因為它會遇到子問題的重疊性。我們可以把問題簡化為累加和與當前值的比較。

找到最優子結構,把每個子問題簡化為

num[i]=Math.max(nums[i-1]+nums[i],nums[i])

記錄歷史狀態,找到最優解。

max=Math.max(max,nums[i])

var maxSubArray = function (nums) {

  let max = nums[0];

  for (let i = 1; i < nums.length; i++) {

      nums[i] = Math.max(nums[i - 1] + nums[i], nums[i])

      max = Math.max(max, nums[i])

  }

  return max

};

sum記錄當前累加和,如果當前累加和小於0,就重置sum。

var maxSubArray = function (nums) {

  let sum=-Infinity,max=-Infinity;

  for(let i=0;i < nums.length;i++){

    if(sum<0){

      sum = nums[i]

    }else{

      sum += nums[i]

    }

    max=Math.max(sum,max)

  }

  return max

};

創建一個dp數組,裡面保存著所有dp[i]的最大子序列和。

var maxSubArray = function (nums) {

  const dp = new Array(nums.length)

  dp[0] = nums[0]

  dp[1] = nums[0]

  for (let i = 2, 

           len = nums.length; 

           i <= len; i++) {

    dp[i] = Math.max(

                nums[i - 1], 

                dp[i - 1] + nums[i - 1])

  }

  return Math.max(...dp)

};

分治法把數組分成兩個相互獨立的子問題來解決。

var maxSubArray = function (nums) {

  // 分治法

  if(nums.length == 0) return -Infinity;

  const divide=(nums, left, right) => {

      if(left == right) return nums[left];

      let mid = (left + right) / 2 | 0;

      // 1. 最大數列和在左邊

      let sumLeft = divide(nums,left,mid);

      // 2. 最大數列和在右邊

      let sumRight = divide(nums,mid+1,right);

      // 3. 最大數列和在中間

      // 先求左邊的最大和

      let leftSum = 0,leftMaxSum = -Infinity;

      for(let i = mid; i >= left; i--){

          leftSum += nums[i];

          leftMaxSum = Math.max(leftMaxSum,leftSum);

      }

      // 求右邊的最大和

      let rightSum = 0,rightMaxSum = -Infinity;

      for(let i = mid + 1; i <= right; i++){

          rightSum += nums[i];

          rightMaxSum = Math.max(rightMaxSum,rightSum);

      }

      return Math.max(

                Math.max(sumLeft,sumRight),

                leftMaxSum+rightMaxSum);

  }

  return divide(nums,0,nums.length-1);

};

主要元素

如果數組中多一半的數都是同一個,則稱之為主要元素。給定一個整數數組,找到它的主要元素。若沒有,返回-1。

示例 1:

輸入:[1,2,5,9,5,9,5,5,5]
輸出:5

示例 2:

輸入:[3,2]
輸出:-1

示例 3:

輸入:[2,2,1,1,1,2,2]
輸出:2

題解:

這題比較簡單,有點類似找字符串中出現次數最多的字符。

var majorityElement = function(nums) {

    let obj = {}

    for(let i of nums){

        obj[i] =!obj[i] ? 1 : ++obj[i]

    }

    for(let i in obj){

        if(obj[i] > (nums.length/2 | 0) ){

            return i

        }

    }

    return -1

};

合併兩個排序列表

輸入兩個遞增排序的鍊表,合併這兩個鍊表並使新鍊表中的節點仍然是遞增排序的。

示例1:

輸入:1->2->4, 1->3->4
輸出:1->1->2->3->4->4

限制:

0 <= 鍊表長度 <= 1000

題解:

需要注意的是遞歸結束條件,以及判斷條件中的返回值。

var mergeTwoLists = function(l1, l2) {

  if (l1 === null) return l2;

  if (l2 === null) return l1;

  if (l1.val < l2.val) {

    l1.next = mergeTwoLists(l1.next, l2);

    return l1;

  } else {

    l2.next = mergeTwoLists(l1, l2.next);

    return l2;

  }

};

借用一個鍊表來存儲。

var mergeTwoLists = function(l1, l2) {

  let current = new ListNode();

  const dummy = current;

  while (l1 || l2) {

    //迭代結束條件

    if (!l1) {

      current.next = l2;

      return dummy.next;

    } else if (!l2) {

      current.next = l1;

      return dummy.next;

    }

    //迭代進行

    if (l1.val <= l2.val) {

      current.next = l1;

      l1 = l1.next;

    } else {

      current.next = l2;

      l2 = l2.next;

    }

    current = current.next;

  }

  return dummy.next;

};

數組中出現次數超過一半的數字

數組中有一個數字出現的次數超過數組長度的一半,請找出這個數字。你可以假設數組是非空的,並且給定的數組總是存在多數元素。

示例 1:

輸入: [1, 2, 3, 2, 2, 2, 5, 4, 2]
輸出: 2

限制:

1 <= 數組長度 <= 50000

題解:

此題與主要元素是相似。

var majorityElement = function (nums) {

  let hash = {}, max = 0, num = nums[0];

  for (let i = 0; i < nums.length; i++) {

    hash[nums[i]]=!hash[nums[i]]?1:++hash[nums[i]]

  }

  for (let key in hash) {

    max = Math.max(max, hash[key])

    if (max == hash[key]) {

      num = key

    }

  }

  return num

};

var majorityElement = function (nums) {

  return nums.sort(((a, b) => a - b))[(nums.length / 2) | 0]

};

最小的k個數

輸入整數數組 arr ,找出其中最小的 k 個數。例如,輸入4、5、1、6、2、7、3、8這8個數字,則最小的4個數字是1、2、3、4。

示例 1:

輸入:arr = [3,2,1], k = 2
輸出:[1,2] 或者 [2,1]

示例 2:

輸入:arr = [0,1,2,1], k = 1
輸出:[0]

限制:

題解:

var getLeastNumbers = function(arr, k) {

  return arr.sort((a, b) => a - b).slice(0, k);

};

利用快排的思想,每經過一輪排序,pivot 左邊的一定是較小的,右邊的一定是較大的。

var getLeastNumbers = function (arr, k) {

  if (arr.length === k) return arr;

  const left = [], right = [];

  const pivot = arr.pop();

  for (let i = 0; i < arr.length; ++i) {

    if (arr[i] <= pivot) {

      left.push(arr[i]);

    } else {

      right.push(arr[i]);

    }

  }

  return left.length < k ? 

          left.concat([pivot])

              .concat(

                    getLeastNumbers(

                        right, k - left.length - 1)) 

          : getLeastNumbers(left, k);

};


希望有更多的小夥伴加入

感謝大家一路的陪伴與堅持

本活動旨在提高群成員的算法思維,每天一道leetcode算法題,需要你註冊https://leetcode-cn.com/力扣官網,程式語言不限。

群管理小雪,每天會監督每位成員,為了提高本成員的自律性。

1、不許發與技術無關的話題,可以討論每天的算法題;

2、成員之間相互尊重;

3、每個工作日早上10點發題,截止晚上10點,每個成員必須發出截圖打卡,約束自己;

4、管理員小雪,每天10點統計,沒有發截圖(打卡)者,會發5元紅包作為統計費用;

5、每周六和周日兩天作為回顧整理,不會發題,不做限制,如果有成員回顧整理成文章,文章精美者,可以獲得10元的獎勵,被收錄在公眾號驚天碼盜。

6、目前leetcode算法題有1055道題,希望大家能一直堅持下來。

1、每個題來自leetcode題庫,出題從簡單到困難;

2、每天管理員會把題的編號和題名,以及截圖發在群裡,成員可以在題庫搜索編號或題名即可查到相應題目;

1、截圖只為約束,如果算法題太難,可以直接查看別人的題解,掌握其思維方式,截圖即可;

2、如果成員覺得題太簡單,可以自行找其他題做,發截圖即可;

如果你有更好的解題思路,請不要吝嗇,歡迎在下方評論。你的參與是最有力的支持,學習重在習慣。

如果你也想參與,公眾號內回復 算法,拉你進群。

相關焦點

  • 每天一道LeetCode算法題——兩數之和
    前言這是博主在LeetCode上刷的第一道題。說來慚愧,算法書看了不止一本,但是看書的時候書裡的練習都沒有怎麼思考,直接看的參考答案,導致了對算法的研究僅僅停留在了解這種程度,缺乏實戰所以在平時coding中也不會將算法知識代入使用。
  • 簡單又常見的算法題:漢諾塔
    ,修煉編程內功)來源:山大王wld算法題儘量做到難易結合,在我們看一些難題的時候偶爾也可以看一些非常簡單又非常容易看懂的題,要不然算法題一直看不懂,容易打擊大家的興趣,今天來看一道非常簡單又非常常見的算法題,就是漢諾塔問題,這道題我想只要是學過編程的同學都應該知道的。
  • 三年級上冊數學期末卷,解決問題專項練習題,最後一道題是難點
    每套數學試卷,最後一道大題都是解決問題,這部分題對於學習好的學生,基本是十拿九穩,可是對於基礎較弱的學生,最後一道大題就被優秀的學生給落下了很多。我今天給大家分享一些解決問題的專項練習題,用來給那些基礎較差的孩子練習一下,打好自己的數學基礎還是很關鍵的。閒話少敘,開始分享試卷。這套試卷一共 有15道大題,滿分也是100分。
  • 每天分享中考數學大題,19年煙臺23題,題型新穎的三角函數題
    對初中數學來說,解答題一直是丟分的重災區,初中生也把大題當作是考試的必爭之地。數學大題究竟如何思考,如何解析?九筒每天分享一道中考數學大題,與大家共同提高。2019年煙臺市中考數學的一道幾何大題,巧妙地將三角函數、勾股定理、科學計算器的使用原理與實際模型結合起來,題型新穎,難度較大,題目質量上乘。這道題究竟妙在哪呢?九筒帶你一起了解這道題吧。
  • 程式設計師面試題,200億個數字找中位數,不給分桶算法,怎麼辦?
    海量數據裡面如何尋找一堆數字的中位數,是一道非常常見的面試題。據稱,這個題目是騰訊前首席技術執行官Tony推崇的一個面試題,被加入的騰訊的面試題題庫。今天我們就來討論下這個題目,有一個存放著200億個數字的文件,存放著32位整型,可能會有重複的數字,現在想從這堆數字中找到他們的中位數。
  • 考你一道題
    所以,但凡是繞點彎的題,我都很難做出來。第一道題:前兩天看到一道題,想半天沒想出來。心裡痒痒,上網搜了答案,還是沒想太明白。 後來聽說亞里斯多德也沒想清楚,我心裡又平衡了。題目如下:這個題的答案,知乎@馬同學有一篇文章講的非常好,可以搜來看看。
  • 腦筋急轉彎:世界上最難的一道題是哪道題?你知道嗎?
    每天分享有趣腦筋急轉彎,等你來挑戰。本期題目「腦筋急轉彎:世界上最難的一道題是哪道題?」答題開始了:腦筋急轉彎一:三更半夜回家才發現忘記帶鑰匙,家裡又沒有其他人在,這時你最大的願望是什麼腦筋急轉彎二:小張把一個雞蛋扔到一米以外的地方去,雞蛋卻沒有破,為什麼?腦筋急轉彎三:老張有很厲害的胃病,可他每周有五天總往牙科跑,這是為什麼?
  • 一道八年級上冊期末數學考試壓軸題,幫你搞定八上所有難點
    一道八年級上冊期末數學壓軸題,幫你搞定八上所有難點!大家好,這裡是數學研討社。每天分享一點初中數學,希望對各位的數學學習有所幫助。也可以點擊關注,私信我們,獲取您所需要的數學乾貨。今天給大家帶來的是一道八年級上冊期末考試壓軸題,上題:題幹:如圖1、一次函數y = - 2x + 2的圖像與y軸交於A點,與X軸交於B點,過點B作線段BC ⊥ AB且BC = AB , 直線AC交X軸於點D第一問:求
  • 字節跳動筆試真題第三彈,2021第一天從算法題開始吧!
    這道題難度同樣不是很大,但是非常考驗基礎,基礎稍稍不夠紮實的同學很有可能寫出了算法,但是依然會陷入各種問題當中無法AC。我個人覺得差不多是LeetCode Medium水平的難度,但是需要大家有點耐心,開動腦筋反覆思考。
  • 一道五年級的數學應用題,「大約需要多少克糖」,家長:題有問題
    這是一道五年級的應用題,題很簡單:一種瓶裝速溶咖啡淨重600克,每衝一杯需要9克咖啡和2.5克糖,衝完這瓶咖啡粉大約需要多少克糖?看看小朋友的解法,根據題意,可以先求出衝的咖啡的杯數,大概是67杯,再求出需要多少的糖。
  • 一道期中壓軸題的思考
    看一道期中測試題:這道題滿分12分,均分不到3分,可謂是「失效題」,絕大多數學生都是靠第一問拿分,第二問能做對的同學鳳毛麟角
  • 區區一道關於織布的小學應用題,又不是國家機密,卻禁止出國展覽
    相信大部分人接觸過小學應用題,對比中學、大學的數學題,難度係數算是比較簡單的,在大眾眼中也頂多算一道普普通通的題目而已,沒有什麼稀奇可言。可是,有這樣一道小學應用題,卻偏偏不走尋常路,還入選了「禁止出國(境)展覽文物」名單,榮耀地肩負著195件(套)「禁出國」文物中唯一的「理科著作」。這消息一出,名震全國。那這道小學應用題的內容到底是什麼呢?區區一道小學應用題,又不是國家機密,卻禁止出國展覽,還名震全國,它究竟有何能耐可以享受如此殊榮呢?
  • 中考物理好題歸納:一道電學實驗題,幾乎概括了全部電學精髓!
    電學習題中,尤其以電學壓軸計算題和電學實驗題為最難做題之最!很多初三的同學們最喜歡做的就是選擇題,其次是填空題和作圖題,當做到實驗題時,多數同學就開始打怵,做到計算題時就莫名緊張。比如說下面這道電學實驗題,幾乎涵蓋了電學中的精髓,非常好的一道中考物理題,如果在研究透徹這一道題,那麼很多相關的電學實驗題就成了小菜一碟。我們來看一下這道題:先看本題的實驗標題:探究電流與電阻的關係。
  • 每天一道數獨題,佳學慧帶你由淺入深學數獨
    但是在連猜帶蒙做了兩道題後就被卡住了。看到練習冊上明明寫的是簡單級別的題,開始懷疑人生。久而久之買來的數獨盤或者練習冊就開始躺在角落裡吃灰了。其實解數獨題也是有方法的,單靠猜測是無法體會到數獨真正獨特魅力的。在接下來的一段時間裡佳學慧會按照由淺入深的方法陸續給大家講解數獨的解題方法。
  • 如何準確、高效地解答一道高中物理題?
    回歸現實,如何完美地解答好一道高中物理題?第一:見題,一眼望穿題目。快速捕捉題境歸屬高中物理哪一塊?也就是此題涉及的環境是什麼?重力場(引力場),彈力,電磁場,光學,熱學,原子物理學,還是原子核?還是兼而有之,複合場。第二:審題。明確環境後,要深入分析。
  • 一道難倒多數初學者的中考物理題!若不深入研究,定會再次犯錯
    這是一道中考物理電學題,對於真正認真地深入研究過這類題的同學來說,應該不算難題,可是,對於多數初學者來說,如果從來沒有接觸過這道題,那就幾乎無從下手了。初三的同學們在學習電學知識時,會遇到各種各樣的習題,今天我們要說的是一道電學實驗題。
  • 考研十二時辰:我見過凌晨5點的太陽
    「北京十二時辰」「上海十二時辰」「山東十二時辰」……陸陸續續結束了地獄式考試周的學生們,也曬出了自己的「暑假十二時辰」。正常的「暑假十二時辰」是不是應該這樣?>卯時(北京時間05時至07時)起床子時(北京時間23時至01時)休息……一天中除了吃飯睡覺,其餘絕大部分時間都在背書、刷題、埋頭苦學。
  • 五分鐘學編程:怎樣才能學好筆試面試最愛考察的算法
    認識算法的N個階段我第一次遇到算法題,還是在我考研複習數據結構的時候,那個時候我看到的算法題其實都是很基礎的題目,比如把數組中的兩個元素置換,把兩個鍊表合併成一個,但對於我來說已經是很有難度的事情了,那時候我連偽代碼是什麼都還不懂。
  • 每日一道中考壓軸題:電路的串、並聯,歐姆定律、電功率計算題
    在考試中,我們一般把最後的綜合題目稱為壓軸題。今天,我們來學習一道中考物理必考的電路的串、並聯、歐姆定律、電功率的壓軸題,有意思的是,這道題是雲南2019年最後三道壓軸題的排名倒數第二,更加顯得重要。分值9分。
  • 說白了,就是槓桿原理丨重慶非物質文化遺產美食故事(第二十二期...
    重慶非物質文化遺產美食故事丨第二十二期//////松溉鹽白菜製作技藝 說白了,就是槓桿原理 鹽白菜是一種必須經過次發酵才能得到的醃製品,就好比炒回鍋肉,肉片第一次下鍋時間再短也是一道不能少的儀式。在醬缸或發酵池底部鋪鹽,鋪完後蓋上一層白菜,再鋪鹽,再鋪菜,然後等個七八天。此時大白菜的內部已充滿了鹽水,看起來,馬上要往泡菜的方向走了。不行,前面左拐。最關鍵的第三步來了:棉幹。