刷leetCode算法題+解析(四十八)

從根到葉的二進制數(shù)之和

題目:給出一棵二叉樹,其上每個結(jié)點的值都是 0 或 1 。每一條從根到葉的路徑都代表一個從最高有效位開始的二進制數(shù)。例如,如果路徑為 0 -> 1 -> 1 -> 0 -> 1,那么它表示二進制數(shù) 01101,也就是 13 。對樹上的每一片葉子,我們都要找出從根到該葉子的路徑所表示的數(shù)字。以 10^9 + 7 為模,返回這些數(shù)字之和。
題目截圖

思路:這道題的思路就是遍歷每一條到葉節(jié)點的二進制數(shù)字,然后取模10的9次方+7,直到遍歷到葉子節(jié)點,則把這個數(shù)值加到結(jié)果sum中。我先去嘗試實現(xiàn)了。
思路沒問題,比想的還要簡單,這個參考了昨天的那道數(shù)組中被5整除的數(shù)的技巧。我直接貼代碼:

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    int sum ; 
    public int sumRootToLeaf(TreeNode root) {
        getNode(root,0);
        return sum;
    }
    public void getNode(TreeNode root ,int i){
       if(root==null) return;
       i = (i*2+root.val)%1000000007;
       //葉子節(jié)點值加到sum中
       if(root!=null && root.left==null && root.right==null) sum += i;
       getNode(root.left,i);
       getNode(root.right,i);
    }
}

因為這個性能直接超過百分百,所以我也不額外看題解了,這道題真的就是一個遍歷+二進制用十進制表示的方法,都很簡單,思路通則路路通。
說起來昨天我做的那個被5整除還是在群友的提點下完成的,表白我群友~好了,下一題。

除數(shù)博弈

題目:愛麗絲和鮑勃一起玩游戲,他們輪流行動。愛麗絲先手開局。最初,黑板上有一個數(shù)字 N 。在每個玩家的回合,玩家需要執(zhí)行以下操作:
選出任一 x,滿足 0 < x < N 且 N % x == 0 。
用 N - x 替換黑板上的數(shù)字 N 。
如果玩家無法執(zhí)行這些操作,就會輸?shù)粲螒颉V挥性趷埯惤z在游戲中取得勝利時才返回 True,否則返回 false。假設(shè)兩個玩家都以最佳狀態(tài)參與游戲。

示例 1:
輸入:2
輸出:true
解釋:愛麗絲選擇 1,鮑勃無法進行操作。
示例 2:
輸入:3
輸出:false
解釋:愛麗絲選擇 1,鮑勃也選擇 1,然后愛麗絲無法進行操作。
提示:

1 <= N <= 1000

思路:就是如題所示。我感覺這道題很復(fù)雜啊,有個最優(yōu)解的問題,就是怎么做能讓對面輸,所以這個除數(shù)可以很多,但是如何選擇最好的那個。。太懵了,我先去看看題目有啥規(guī)律。
好了,算是找到規(guī)律了。但是不知道對不對。我反正是自己一個個數(shù)導(dǎo)的,又是眼睛看出來的規(guī)律。

一個數(shù)一個數(shù)排查

我去提交了,看看對不對。
提交結(jié)果

事實證明就是這么簡單,這道題就這樣吧。

兩地調(diào)度

題目:公司計劃面試 2N 人。第 i 人飛往 A 市的費用為 costs[i][0],飛往 B 市的費用為 costs[i][1]。返回將每個人都飛到某座城市的最低費用,要求每個城市都有 N 人抵達。

示例:
輸入:[[10,20],[30,200],[400,50],[30,20]]
輸出:110
解釋:
第一個人去 A 市,費用為 10。
第二個人去 A 市,費用為 30。
第三個人去 B 市,費用為 50。
第四個人去 B 市,費用為 20。
最低總費用為 10 + 30 + 50 + 20 = 110,每個城市都有一半的人在面試。
提示:

1 <= costs.length <= 100
costs.length 為偶數(shù)
1 <= costs[i][0], costs[i][1] <= 1000

思路:這個題第一反應(yīng)是復(fù)雜,甚至都想到了動態(tài)規(guī)劃(最近在學(xué)dp,看到啥都想到),后來要實現(xiàn)了才發(fā)現(xiàn)沒有那么難。其實可以這么想,一個人去a和去b兩種選擇??隙ㄊ且ヒ粋€地方,主要區(qū)別就是錢的差值。打個比方:a這個人去A100,去B110.然后b這個人去A10,去B50。我們不用考慮100,110,10,50這四個數(shù)的比較,只要知道a去A比B便宜10.而b去A比B便宜40??隙ㄊ沁x擇便宜的多的,也就是a去B,b去A。這個邏輯繞明白了就能明白這道題的做法了。
其實我說的比較亂,因為思路也是才理出來。但是方向應(yīng)該是對的。每個人只要和自身比較就行了,不要和別人比較。目前的想法是都假設(shè)去A。然后再比較去B要便宜的錢數(shù)(如果本身B比A大這個錢數(shù)就是負數(shù)。)然后找出一般的人選擇便宜的錢數(shù)最多的。差不多就這樣,我去實現(xiàn)了先。
這個題做出來了,中間有一些波折,有一個測試案例沒通過,這個題的參數(shù)是數(shù)組型數(shù)組,java中創(chuàng)建只能一個個往里填,所以我沒辦法用debug調(diào)試知道到底哪里錯了,所以很痛苦,眼睛看數(shù)組都花了也沒看出錯誤,所以中間試圖打算將數(shù)組換成隊列來做這道題,就是之前刷算法用到的一個自帶排序的queue。PriorityBlockingQueue。不過還好改動不小,并且在改動的時候靈機一動感覺找到了不正確的點,所以~~~過了,哈哈,一波三折啊有么有?
我直接貼實現(xiàn)的代碼:

class Solution {
    public int twoCitySchedCost(int[][] costs) {
        int sum = 0;
        //去a和去b的差值不會大于999,所以數(shù)組長度2000是包含正負
        int[] ar = new int[2000];
        for(int [] i :costs ){
            sum += i[0];
            //這個i[1]-i[0]是說去b比去a貴的。如果是正數(shù)要減去
            ar[i[1]-i[0]+1000] ++; 
        }
        int index = 0;
        int i = 0;
        while(i<costs.length/2){
            while(ar[index]>0&&i<costs.length/2){
                sum += (index-1000);
                ar[index]--;
                i++;
            }
            index++;
        }
        return sum;        
    }
}

這個題用到了常用的技巧數(shù)組下標代替數(shù)值,因為這個值可能是負的所以我這里都統(tǒng)一加了1000、一開始我錯誤的點就是第二個while中只判斷了ar[index]大于0而沒判斷i,這也算是一個失誤了,思慮不周而且這種情況我自己測試案例沒測出來,講真leetcode測試案例很強大啊。
這個性能是超過百分之九十九的,所以我也不再換方法了。不過講真,我現(xiàn)在也覺得之前我想的那個排序隊列也是可以實現(xiàn)的,只不過我是真的懶得大刀。
這道題就到這里吧,感覺雖然只做了這一道題,但是不斷在復(fù)習(xí)之前學(xué)到的知識,比如數(shù)組下標代替數(shù)值 ,還有隊列啊,其實不斷刷題的過程也是一個復(fù)習(xí)的過程~~下一題。

距離順序排列矩陣單元格

題目:給出 R 行 C 列的矩陣,其中的單元格的整數(shù)坐標為 (r, c),滿足 0 <= r < R 且 0 <= c < C。另外,我們在該矩陣中給出了一個坐標為 (r0, c0) 的單元格。返回矩陣中的所有單元格的坐標,并按到 (r0, c0) 的距離從最小到最大的順序排,其中,兩單元格(r1, c1) 和 (r2, c2) 之間的距離是曼哈頓距離,|r1 - r2| + |c1 - c2|。(你可以按任何滿足此條件的順序返回答案。)

示例 1:
輸入:R = 1, C = 2, r0 = 0, c0 = 0
輸出:[[0,0],[0,1]]
解釋:從 (r0, c0) 到其他單元格的距離為:[0,1]
示例 2:
輸入:R = 2, C = 2, r0 = 0, c0 = 1
輸出:[[0,1],[0,0],[1,1],[1,0]]
解釋:從 (r0, c0) 到其他單元格的距離為:[0,1,1,2]
[[0,1],[1,1],[0,0],[1,0]] 也會被視作正確答案。
示例 3:
輸入:R = 2, C = 3, r0 = 1, c0 = 2
輸出:[[1,2],[0,2],[1,1],[0,1],[1,0],[0,0]]
解釋:從 (r0, c0) 到其他單元格的距離為:[0,1,1,2,2,3]
其他滿足題目要求的答案也會被視為正確,例如 [[1,2],[1,1],[0,2],[1,0],[0,1],[0,0]]。
提示:

1 <= R <= 100
1 <= C <= 100
0 <= r0 < R
0 <= c0 < C

思路:這個題我第一遍審題沒明白,然后畫圖理解的:首先行列確定了這個二維塊的大小。其次這個r0,c0確定了起始點。然后我們從起始點(距離是0,肯定是最小的)開始按照距離一個個列出來。

草圖??!真的很草

當(dāng)然還有一個距離的規(guī)律:
第一個點最多有4個距離1的點,8個距離2 的點,12個距離3的點,其實不用往下繼續(xù)標也能看出來,應(yīng)該是16個距離4的點,20個距離5的點。暫時還不知道這個規(guī)律有沒有用,反正先放著。
距離規(guī)律

其實這個自己畫兩遍就能理解題意了,這個最外層的點是不算的。

  • 比如1行1列,則只有一個點0 0 是有效的。
  • 一行兩列則只有原點 0 0和 0 1是有效的。別的點都在邊邊上,不算有效。
  • 同樣道理,2行三列拋出去最外層的邊邊,相當(dāng)于位于2-3之間的有效,也就是6個點。
    其實這里要說一下,因為坐標的值從0開始,所以點數(shù)哪怕不包含最外面的,但是恰好了,1不包含最外的但是包含0一個點,2不包含最外的2但是包含0,1也是兩個點。所以點數(shù)就是行列數(shù)(其實用二維數(shù)組更好理解,元素個數(shù)就是兩個長度的乘積)
    到這為止,起碼返回值中的點的個數(shù)是知道了的。然后一個點分行列兩個坐標。坐標好得,關(guān)鍵是距離的大小。最笨的辦法就是都算出返回值,挨個算距離。
    但是其實我感覺也不見得沒有簡單算法。比如我們可以以給定點為基點,直接在獲取坐標的時候就按照距離獲取。當(dāng)然了這些都是想法, 我要去擼代碼實現(xiàn)了。
    emmmm....首先實現(xiàn)了,其次沒什么簡單算法,我沒想出來,最后暴力sort解決的,我先貼代碼:
class Solution {
    public int[][] allCellsDistOrder(int R, int C, int r0, int c0) {
        int[][] res = new int[R*C][2];
        int k = 0;
        for(int i = R-1;i>=0;i--){
            for(int j = C-1;j>=0;j--){
                res[k] = new int[]{i,j};
                k++;
            }
        }
        Arrays.sort(res,new Comparator<Object>() {
            @Override
            public int compare(Object arg0, Object arg1) {
                int[] aa = (int[])arg0;
                int[] bb = (int[])arg1;
                int a = Math.abs(aa[0]-r0)+Math.abs(aa[1]-c0);
                int b = Math.abs(bb[0]-r0)+Math.abs(bb[1]-c0);
                return Integer.compare(a,b);
            }       
        });
        return res;
    }
}

分兩步:

  1. 獲取所有的點
  2. 給點按照距離排序

自己寫的排序規(guī)則。然后性能湊合,雖然執(zhí)行速度不盡人意,但是內(nèi)存消耗超過百分百,也算是有點優(yōu)點了。


image.png

然后雖然我沒想出來。但是我還是覺得應(yīng)該是有簡單算法的啊,明明知道規(guī)律卻寫不出來,就是 給定r0 和c0和實際的大小的判斷。。。哎,我決定還是直接看排行第一的代碼吧。
很好,直接給我解惑了。我當(dāng)時有這個想法,但是一來比較麻煩,二來不確定是不是對的所以沒有堅持,但是大體分四種情況都想到了,這種我沒做出來別人做到了的感覺,,,嘖嘖,貼上代碼瞻仰瞻仰:

class Solution {
    public int[][] allCellsDistOrder(int R, int C, int r0, int c0) {
        int[][] ans=new int[R*C][2];
        ans[0][0]=r0;
        ans[0][1]=c0;
        int point_x=r0,point_y=c0;
        int order=1;
        while(order<R*C){
            point_x--;
            while(point_x<r0){
                if(point_x>=0&&point_y<=C-1){
                    ans[order][0]=point_x;
                    ans[order++][1]=point_y;
                }
                point_x++;
                point_y++;
            }
            while(point_y>c0){
                if(point_x<=R-1&&point_y<=C-1){
                    ans[order][0]=point_x;
                    ans[order++][1]=point_y;
                }
                point_x++;
                point_y--;
            }
            while(point_x>r0){
                if(point_x<=R-1&&point_y>=0){
                    ans[order][0]=point_x;
                    ans[order++][1]=point_y;
                }
                point_x--;
                point_y--;
            }
            while (point_y<c0){
                if(point_x>=0&&point_y>=0){
                    ans[order][0]=point_x;
                    ans[order++][1]=point_y;
                }
                point_x--;
                point_y++;
            }
        }
        return ans;
    }
}

好的吧,我仔細看了第一二三的代碼,都是這樣分情況直接往里插入就是準確的,其實我也是前期準備做了一堆,寫代碼的時候懶了。。。哈哈,反正就這樣吧。這道題過。

移動石子直到連續(xù)

題目:三枚石子放置在數(shù)軸上,位置分別為 a,b,c。每一回合,我們假設(shè)這三枚石子當(dāng)前分別位于位置 x, y, z 且 x < y < z。從位置 x 或者是位置 z 拿起一枚石子,并將該石子移動到某一整數(shù)位置 k 處,其中 x < k < z 且 k != y。當(dāng)你無法進行任何移動時,即,這些石子的位置連續(xù)時,游戲結(jié)束。要使游戲結(jié)束,你可以執(zhí)行的最小和最大移動次數(shù)分別是多少? 以長度為 2 的數(shù)組形式返回答案:answer = [minimum_moves, maximum_moves]

示例 1:
輸入:a = 1, b = 2, c = 5
輸出:[1, 2]
解釋:將石子從 5 移動到 4 再移動到 3,或者我們可以直接將石子移動到 3。
示例 2:
輸入:a = 4, b = 3, c = 2
輸出:[0, 0]
解釋:我們無法進行任何移動。
提示:

1 <= a <= 100
1 <= b <= 100
1 <= c <= 100
a != b, b != c, c != a

思路:我完全不知道這個題是怎么混進來的、感覺很簡單啊。我不知道有什么坑,所以去試試。做出來再說。
好了,做出來了,反正就是很簡單的一個邏輯,不過中間也有坑,本來我以為a,b,c小到大和xyz是對應(yīng)的,現(xiàn)在才知道是隨機的,所以要知道最大值最小值和中間值。另外一步到位可以跳過y去另一邊,反正說到底都是面上的東西,不復(fù)雜。直接貼代碼:

class Solution {
    public int[] numMovesStones(int a, int b, int c) {
        int max = a>b?a:b;
        max =max>c?max:c;
        int min = a>b?b:a;
        min = min>c?c:min;
        int mid = a+b+c-min-max;
        
        int[] res = new int[2];         
        res[1] += max-1-mid; 
        res[1] += mid-1-min;
        if(mid==min+1 && max==mid+1){
            res[0] = 0;
        }else if(mid!=min+1 && max!=mid+1 && mid!=min+2 && max!=mid+2){
            res[0] =2;
        }else{
            res[0]=1;
        }
        return res;
        
    }
}

有效的回旋鏢

題目:回旋鏢定義為一組三個點,這些點各不相同且不在一條直線上。給出平面上三個點組成的列表,判斷這些點是否可以構(gòu)成回旋鏢。

示例 1:
輸入:[[1,1],[2,3],[3,2]]
輸出:true
示例 2:

輸入:[[1,1],[2,2],[3,3]]
輸出:false
提示:
points.length == 3
points[i].length == 2
0 <= points[i][j] <= 100

思路:這樣的題我做過類似的,但是這個題讓我有點疑問啊,題目說的意思是不是只要能構(gòu)成三角形的三個點就有效?不用扔前扔后距離相等?我記得上一個回旋鏢的題是有這個要求的啊,我去拿個demo試試。
好的,已經(jīng)確定能組成三角形就行了。

測試demo

那這個題不是簡單的的不得了了么?只要三個點橫縱坐標不一樣且與x/y軸夾角不一樣就行了。我去實現(xiàn)了。
這個實現(xiàn)一波三折,因為是程序代碼,涉及到除法int型會取整,所以小數(shù)除大數(shù)都是0.沒法比較,所以我的想法太理所當(dāng)然了。pass
然后自己想了半天,最后求助百度了,其實這個題就是判斷三點是不是一線。
判斷三點是不是一線

所以說最終就這么做完了。
其實這個算是學(xué)到了新的數(shù)學(xué)知識了吧。
而且不用這種辦法另外一種就是兩點連線,判斷這個第三個點在不在線上,想想都麻煩,還是這個方法最簡單。這個題就這樣吧

class Solution {
    public boolean isBoomerang(int[][] points) {
        int x1 = points[0][0];
        int y1 = points[0][1];
        int x2 = points[1][0];
        int y2 = points[1][1];
        int x3 = points[2][0];
        int y3 = points[2][1];        
        //令R1=x2-x1,C1=y2-y1;R2=x3-x2,C2=y3-y2。如果R1*C2=R2*C1,那么這三個點就在同一條線上。
        if((x2-x1)*(y3-y2)==(y2-y1)*(x3-x2))return false;        
        return true;
    }
}

今天的筆記就記到這里,如果稍微幫到你了記得點個喜歡點個關(guān)注,也祝大家工作順順利利!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,578評論 6 544
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,701評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 178,691評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,974評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 72,694評論 6 413
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 56,026評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,015評論 3 450
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 43,193評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,719評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 41,442評論 3 360
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,668評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,151評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,846評論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,255評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,592評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,394評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 48,635評論 2 380

推薦閱讀更多精彩內(nèi)容