leetCode進(jìn)階算法題+解析(六十三)

輸出二叉樹

題目:在一個(gè) m*n 的二維字符串?dāng)?shù)組中輸出二叉樹,并遵守以下規(guī)則:
行數(shù) m 應(yīng)當(dāng)?shù)扔诮o定二叉樹的高度。
列數(shù) n 應(yīng)當(dāng)總是奇數(shù)。
根節(jié)點(diǎn)的值(以字符串格式給出)應(yīng)當(dāng)放在可放置的第一行正中間。根節(jié)點(diǎn)所在的行與列會(huì)將剩余空間劃分為兩部分(左下部分和右下部分)。你應(yīng)該將左子樹輸出在左下部分,右子樹輸出在右下部分。左下和右下部分應(yīng)當(dāng)有相同的大小。即使一個(gè)子樹為空而另一個(gè)非空,你不需要為空的子樹輸出任何東西,但仍需要為另一個(gè)子樹留出足夠的空間。然而,如果兩個(gè)子樹都為空則不需要為它們留出任何空間。
每個(gè)未使用的空間應(yīng)包含一個(gè)空的字符串""。
使用相同的規(guī)則輸出子樹。
題目截圖

思路:這個(gè)題怎么說呢,首先層數(shù)和list的元素?cái)?shù)的關(guān)系:1-1 。2-3。3-7。4-15.就是上一個(gè)翻倍+1.翻倍就是左右,加1是中間。到這里思路還是很清楚的。然后先把二維數(shù)組列出來,往里一層一層填充元素得了。估計(jì)這個(gè)填充還要dfs。我去試試代碼。
這個(gè)題特別有意思。我寫個(gè)n個(gè)方法,以為低空略過,結(jié)果一次ac性能超過百分百。先貼代碼:

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    int d = 0;
    public List<List<String>> printTree(TreeNode root) {
        List<List<String>> res = new ArrayList<List<String>>();
        dfs(0, root);
        int len = 1;
        for(int i = 1;i<d;i++) len = len*2 + 1;
        for(int i = 0;i<d;i++){
            List<String> list = new ArrayList<String>();
            for(int j = 0;j<len;j++) list.add("");
            res.add(list);            
        }
        dfs(res, root, 0, len-1, 0);
        return res;
    }
    public void dfs(List<List<String>> res,TreeNode root,int start,int end,int len) {
        if(root != null) {
            int mid = (start+end)>>1;//因?yàn)橄聵?biāo)從0開始。所以這里的結(jié)果正好是中間那個(gè)
            res.get(len).set(mid, String.valueOf(root.val));
            dfs(res, root.left, start, mid-1, len+1);
            dfs(res, root.right, mid+1, end, len+1);
        }
    }
    public void dfs(int temp,TreeNode root){
        if(root.left == null && root.right == null) d = Math.max(d, temp+1);
        if(root.left != null) dfs(temp+1, root.left);
        if(root.right != null) dfs(temp+1,root.right);
    }
}

大概的思路和預(yù)計(jì)的差不多,先獲取這個(gè)二維數(shù)組的長寬。把空串填進(jìn)去。然后再根據(jù)樹一個(gè)一個(gè)元素替換,這里用了兩次遞歸:一次是找樹的高度。一次是填充元素。這么多代碼我都快以為是我想錯(cuò)了,沒成想這個(gè)題目就是這樣的。剛剛看了下性能第一的代碼和我這個(gè)思路差不多,所以這個(gè)題就這樣了,下一題。

找到k個(gè)最接近的元素

題目:給定一個(gè)排序好的數(shù)組 arr ,兩個(gè)整數(shù) k 和 x ,從數(shù)組中找到最靠近 x(兩數(shù)之差最?。┑?k 個(gè)數(shù)。返回的結(jié)果必須要是按升序排好的。整數(shù) a 比整數(shù) b 更接近 x 需要滿足:|a - x| < |b - x| 或者|a - x| == |b - x| 且 a < b

示例 1:
輸入:arr = [1,2,3,4,5], k = 4, x = 3
輸出:[1,2,3,4]
示例 2:
輸入:arr = [1,2,3,4,5], k = 4, x = -1
輸出:[1,2,3,4]
提示:
1 <= k <= arr.length
1 <= arr.length <= 104
數(shù)組里的每個(gè)元素與 x 的絕對值不超過 104

思路:這個(gè)題怎么說呢,我個(gè)人感覺是分兩部分:1.找出這些數(shù)。2.這些數(shù)字升序排列。至于怎么找出這些數(shù)應(yīng)該是從給定數(shù)字往兩頭外擴(kuò)吧。比如demo中從3開始兩邊擴(kuò)充(3本身要入結(jié)果集):2.4值一樣,但是2小,所以2入結(jié)果集。再往下1,4中4絕對值小,所以4入結(jié)果集。再往下1,5絕對值一樣但是1小,1入結(jié)果集。這個(gè)時(shí)候結(jié)果集滿了,所以返回。。。思路很清楚,我去寫代碼了。
第一版本代碼出來了,雖然ac的但是性能有點(diǎn)問題,我先貼出來:

class Solution {
    public List<Integer> findClosestElements(int[] arr, int k, int x) {
        int len = arr.length-1;     
        int idx = -1;
        if(arr[0]>=x) {//最小的數(shù)都大于x
            idx = 0;
        }else if(arr[len]<=x) {//最大的小于x。
            idx = len;
        }else {
            for(int i = 0;i<len;i++) {
                if(arr[i] == x) {
                    idx = i;
                    break;
                }else if(arr[i]<x && arr[i+1]>x) {//x沒落在正好的位置
                    idx = arr[i+1]-x<x-arr[i]?i+1:i;//返回距離比較近的那個(gè).相等返回小的
                    break;
                }
            }
        }
        List<Integer> res = new ArrayList<Integer>();
        res.add(arr[idx]);//最接近的元素直接放進(jìn)去
        //從idx開始雙指針往外找。
        int left = idx;
        int right = idx;
        //結(jié)果集沒滿就繼續(xù)填充
        while(res.size()<k) {
            if(right==len) {//不能往后指了,只能往前走
                res.add(arr[--left]);
            }else if(left == 0){
                res.add(arr[++right]);
            }else {
                //后面的絕對值小選擇后面的,否則選擇前面的
                if((arr[right+1]-x)<(x-arr[left-1])) {
                    res.add(arr[++right]);
                }else {
                    res.add(arr[--left]);
                }
            }
        }
        Collections.sort(res);
        return res;
    }
}

這個(gè)題怎么說呢,暫時(shí)優(yōu)化思路都莫得,我感覺寫的挺好的啊,我直接去看看性能第一的代碼吧:

class Solution {
    public List<Integer> findClosestElements(int[] arr, int k, int x) {
        int left = 0, right = k - 1;
        
        while (right + 1 < arr.length && (arr[right + 1] <= x 
                        || arr[right + 1] - x < x - arr[left])) {
            left++;
            right++;
        }
        
        List<Integer> result = new ArrayList<>();
        for (int i = left; i <= right; i++) {
            result.add(arr[i]);
        }
        
        return result;
    }
}

為什么都想到雙指針了卻沒想到滑窗啊?。?!為什么可以這么菜!!心態(tài)崩了啊,反正這個(gè)性能第一的代碼就是一個(gè)滑窗。因?yàn)槭沁f增序列。所以符合條件的結(jié)果集一定是一串挨著的元素。重點(diǎn)是判斷出從哪里開始的連續(xù)數(shù)組中元素而已。
一看這個(gè)思路我就會(huì)了,但是自己就是琢磨不出來,哭了啊~最近刷題刷的心態(tài)爆炸,感覺刷了這么久還是沒什么進(jìn)步。做題靠直覺,思路純暴力。哎,下一題下一題。

買賣股票的最佳時(shí)機(jī)含手續(xù)費(fèi)

題目:給定一個(gè)整數(shù)數(shù)組 prices,其中第 i 個(gè)元素代表了第 i 天的股票價(jià)格 ;非負(fù)整數(shù) fee 代表了交易股票的手續(xù)費(fèi)用。你可以無限次地完成交易,但是你每筆交易都需要付手續(xù)費(fèi)。如果你已經(jīng)購買了一個(gè)股票,在賣出它之前你就不能再繼續(xù)購買股票了。返回獲得利潤的最大值。注意:這里的一筆交易指買入持有并賣出股票的整個(gè)過程,每筆交易你只需要為支付一次手續(xù)費(fèi)。

示例 1:
輸入: prices = [1, 3, 2, 8, 4, 9], fee = 2
輸出: 8
解釋: 能夠達(dá)到的最大利潤:
在此處買入 prices[0] = 1
在此處賣出 prices[3] = 8
在此處買入 prices[4] = 4
在此處賣出 prices[5] = 9
總利潤: ((8 - 1) - 2) + ((9 - 4) - 2) = 8.
注意:
0 < prices.length <= 50000.
0 < prices[i] < 50000.
0 <= fee < 50000.

思路:這個(gè)題我不記得我做沒做過了,是今天的每日一題。買賣股票這塊作為dp的經(jīng)典題目,我記得我當(dāng)年統(tǒng)一刷過啊。話不多說,說解題思路。首先這個(gè)手續(xù)費(fèi)只收一筆,所以我們可以設(shè)置為在買入的時(shí)候比實(shí)際價(jià)格貴fee元。其次有一個(gè)概念:峰值一定是賣出或者留手,不可能最貴的時(shí)候買入。當(dāng)然同理肯定是在谷值買入,不然不會(huì)買貴的不買便宜的。所以說這個(gè)題可以先把prices簡化成峰值谷值峰值谷值。然后上一次賣不賣和這一次買不買是dp關(guān)系。差不多思路就這樣,我再去結(jié)合題目試著寫代碼吧。
怎么說呢,ac倒是ac了,但是性能不咋地,而且最后也不是dp實(shí)現(xiàn)的。先貼代碼:

class Solution {
    public int maxProfit(int[] prices, int fee) {
        int res = 0;
        if(prices.length <2) return 0;//不管是沒有元素還是只有一個(gè)元素都不買,0收益
        //手續(xù)費(fèi)可以算成是買入的時(shí)候+fee元。
        //有一個(gè)概念:峰值一定是賣出或者留手,不可能最貴的時(shí)候買入
        //不可能非谷值買入。干嘛不買便宜的買貴的?
        //所以說這個(gè)題可以先把prices簡化成峰值谷值峰值谷值。。
        //因?yàn)橘I入加手續(xù)費(fèi),所以谷值直接+fee.第一個(gè)肯定是谷值
        //所以說只要低價(jià)買入能賺就賣出就買
        
        //因?yàn)橘I入要手續(xù)費(fèi),所以這個(gè)手續(xù)費(fèi)直接算到買入價(jià)格
        int buy = prices[0]+fee;
        for(int i = 1;i<prices.length;i++) {
            if(buy>prices[i]+fee) {//挑便宜的買,所以要替換買入價(jià)格
                buy = prices[i] + fee;
            }else if (prices[i]>buy){//現(xiàn)在買入的比價(jià)格賣了就是賺的,所以賣
                res += prices[i]-buy;//賺的錢增加了
                //因?yàn)檫@個(gè)prices[i]是賣出價(jià)格。有比這個(gè)價(jià)格高的直接這個(gè)不買下一個(gè)賣
                //所以這個(gè)不用+fee。當(dāng)然如果再遇到比這個(gè)便宜的會(huì)重新買入。
                buy = prices[i];
            }
        }
        return res;     
    }
}

這種題目的一個(gè)特點(diǎn):思路理順了做起來會(huì)簡單的多。我覺得只要給我時(shí)間dp也不是不能實(shí)現(xiàn),不過在寫的過程中靈機(jī)一動(dòng)發(fā)現(xiàn)這個(gè)其實(shí)不非要用dp。就是峰值谷值看了半天看出了規(guī)律:倒手掙錢就倒手。dp規(guī)律就是峰值谷值/下一次谷峰差值加上當(dāng)前的大就檔次轉(zhuǎn)手再買再賣。否則一直留股到下次一起賣。我再去試試dp實(shí)現(xiàn):

class Solution {
    public int maxProfit(int[] prices, int fee) {
        int res = 0;
        if(prices.length <2) return 0;//不管是沒有元素還是只有一個(gè)元素都不買,0收益
        int buy = -prices[0];//記錄前一天的狀態(tài),手里持股
        int sell = 0;//前一天的狀態(tài),手里不持股
        for(int i = 1;i<prices.length;i++) {
            //這一天的狀態(tài)是手里持股,那么就在前一天的基礎(chǔ)上買股,要么就是不買股
            buy = Math.max(buy, sell-prices[i]);
            //這一天的狀態(tài)是手里不持股的話,前一天沒股和前一天持股但是賣掉哪個(gè)合適
            sell = Math.max(sell, buy+prices[i]-fee);
        }
        //最終一定是不持股的狀態(tài)
        return sell;        
    }
}

真的有時(shí)候一開始思路有問題很難中途轉(zhuǎn)過來。dp本身和峰值谷值莫得關(guān)系。只要判斷當(dāng)前的最優(yōu)解就行了。每一天分兩種狀態(tài):當(dāng)前手里有股票,當(dāng)前手里沒股票。
我們只需要選擇每一天都是最優(yōu)解就行了。 手里不持股買當(dāng)天的和手里持以前的股,哪個(gè)賺的更多選擇哪個(gè)。同理當(dāng)天賣股票還是前一天賣股票哪個(gè)更賺錢就選擇哪個(gè)。
我剛剛看了下題解,這個(gè)可以用二維dp數(shù)組來實(shí)現(xiàn)。不過因?yàn)檫@個(gè)題只和上一天的狀態(tài)有關(guān),所以不用數(shù)組,用變量保存上一天的狀態(tài)就行了。
反正完整版的代碼如下,這個(gè)題也就這樣了,下一題。

二叉樹最大寬度

題目:給定一個(gè)二叉樹,編寫一個(gè)函數(shù)來獲取這個(gè)樹的最大寬度。樹的寬度是所有層中的最大寬度。這個(gè)二叉樹與滿二叉樹(full binary tree)結(jié)構(gòu)相同,但一些節(jié)點(diǎn)為空。每一層的寬度被定義為兩個(gè)端點(diǎn)(該層最左和最右的非空節(jié)點(diǎn),兩端點(diǎn)間的null節(jié)點(diǎn)也計(jì)入長度)之間的長度。
題目截圖

題目截圖

思路:這個(gè)題怎么說呢,審題幾遍才看懂。我目前的想法就是遍歷。所有不是首個(gè)節(jié)點(diǎn)的非空節(jié)點(diǎn)用null填充。最終統(tǒng)計(jì)每一次的有效元素?cái)?shù)(首尾不是null的)。我大概會(huì)用0,1來表示吧,有個(gè)簡單的思路,我去實(shí)現(xiàn)下。
第一個(gè)版本的代碼超時(shí)了,雖然我自認(rèn)為邏輯沒錯(cuò):

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public int widthOfBinaryTree(TreeNode root) {
        int res = 0;
        Queue<TreeNode> queue = new LinkedList<TreeNode>();
        queue.add(root);
        while(!queue.isEmpty()) {
            int start = -1;
            int end = -1;
            int size = queue.size();
            for(int i = 0;i<size;i++) {
                TreeNode temp = queue.poll();
                if(temp!=null && start == -1) start = i;//第一個(gè)有值的元素要記錄  
                if(temp!=null) end = i;//最后一個(gè)有值的元素記錄
                //當(dāng)前元素非空添加兩個(gè)子節(jié)點(diǎn)
                if(temp != null) {
                    queue.add(temp.left);
                    queue.add(temp.right);
                }else if(start != -1){//有了非空元素才需要占位
                    queue.add(null);
                    queue.add(null);
                }
            }
            res = Math.max(res, end-start+1);
            //這一層都沒有元素的了,說明樹遍歷完了
            if(start == -1) return res;
        }
        return res;
    }
}

當(dāng)然也可能是做了很多無用功。而且我看了測試案例,覺得可能這種每一個(gè)元素都列出來是有問題的,我去想想優(yōu)化思路。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public int widthOfBinaryTree(TreeNode root) {
        int res = 0;
        LinkedList<TreeNode> queue = new LinkedList<>();
        LinkedList<Integer> indexQueue = new LinkedList<>();
        queue.add(root);
        indexQueue.add(1);
        while (!queue.isEmpty()) {
            int left = indexQueue.peek();
            int len = queue.size();
            for (int i = 0; i < len; i++) {
                TreeNode poll = queue.poll();
                Integer index = indexQueue.poll();
                res = Math.max(res, index - left + 1);
                if (poll.left != null) {
                    queue.add(poll.left);
                    indexQueue.add(index * 2);
                }
                if (poll.right != null) {
                    queue.add(poll.right);
                    indexQueue.add(index * 2 + 1);
                }
            }
        }
        return res;
    }
}

這個(gè)題我自己優(yōu)化了三個(gè)版本才發(fā)現(xiàn),我沒必要一直想著剪枝(中間有一個(gè)版本end后面的刪除)。重點(diǎn)是這個(gè)null就沒必要占位。因?yàn)槠鋵?shí)根據(jù)父節(jié)點(diǎn)一層一層就能推導(dǎo)出當(dāng)前節(jié)點(diǎn)按照滿樹來講所在的位置、同樣能能推算出結(jié)束節(jié)點(diǎn)所在位置。這樣不用null占位也知道中間隔了多少個(gè)值。于是最終版代碼出現(xiàn)了,所有入隊(duì)列的元素都是非空的,省去了很多性能。同樣根據(jù)下標(biāo)的位置判斷最大差值。反正這個(gè)題的思路就這樣了,我去看看題解吧。
看了性能排行第一的代碼:


/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */

class Solution {
    public int widthOfBinaryTree(TreeNode root) {
        if(root == null) {
            return 0;
        }

        Deque<TreeNode> queue = new LinkedList<>();
        // 根節(jié)點(diǎn)編號為 0
        root.val = 0;
        queue.add(root);

        int sum;
        int ans = 0;
        while(!queue.isEmpty()) {
            sum = queue.size();
            // 隊(duì)頭和隊(duì)尾的編號值求差用來更新寬度
            ans = Math.max(ans, queue.getLast().val - queue.getFirst().val + 1);
            // 一次處理一層,進(jìn)入這個(gè)循環(huán)前隊(duì)列中是一層的所有非空節(jié)點(diǎn)
            while(sum > 0) {
                TreeNode temp = queue.remove();

                // 子節(jié)點(diǎn)入隊(duì)前修改 val, val = 滿二叉樹中節(jié)點(diǎn)編號
                if(temp.left != null) {
                    queue.add(temp.left);
                    temp.left.val = temp.val * 2 + 1;
                }
                if(temp.right != null) {
                    queue.add(temp.right);
                    temp.right.val = temp.val * 2 + 2;
                }
                sum--;
            }
        }
        return ans;
    }
}

先說一下這個(gè)題用的雙端隊(duì)列。我之前有想到這個(gè)數(shù)據(jù)結(jié)構(gòu)。但是沒用。以為影響不會(huì)很大。其次兩點(diǎn)就是用樹節(jié)點(diǎn)的值表示當(dāng)前所在位置。這個(gè)挺新穎的一個(gè)思路。相比于上面兩個(gè)隊(duì)列對應(yīng)的代碼這個(gè)可能更好計(jì)算一點(diǎn)吧。有時(shí)候不得不感慨大家長的是一個(gè)腦子么。。。這種代碼屬于看了能理解,自己想不出來的東西。這個(gè)題主要就是二叉樹位置的計(jì)算-樹的左節(jié)點(diǎn)位置是父節(jié)點(diǎn)位置2.右節(jié)點(diǎn)為止是父節(jié)點(diǎn)位置2+1。
只要知道這兩個(gè)公式這個(gè)題做還是能做出來的,下一題了。

優(yōu)美的排序2

題目:給定兩個(gè)整數(shù) n 和 k,你需要實(shí)現(xiàn)一個(gè)數(shù)組,這個(gè)數(shù)組包含從 1 到 n 的 n 個(gè)不同整數(shù),同時(shí)滿足以下條件:
  • ① 如果這個(gè)數(shù)組是 [a1, a2, a3, ... , an] ,那么數(shù)組 [|a1 - a2|, |a2 - a3|, |a3 - a4|, ... , |an-1 - an|] 中應(yīng)該有且僅有 k 個(gè)不同整數(shù);.
  • ② 如果存在多種答案,你只需實(shí)現(xiàn)并返回其中任意一種.

示例 1:
輸入: n = 3, k = 1
輸出: [1, 2, 3]
解釋: [1, 2, 3] 包含 3 個(gè)范圍在 1-3 的不同整數(shù), 并且 [1, 1] 中有且僅有 1 個(gè)不同整數(shù) : 1
示例 2:
輸入: n = 3, k = 2
輸出: [1, 3, 2]
解釋: [1, 3, 2] 包含 3 個(gè)范圍在 1-3 的不同整數(shù), 并且 [2, 1] 中有且僅有 2 個(gè)不同整數(shù): 1 和 2
提示:
n 和 k 滿足條件 1 <= k < n <= 104.

思路:簡單說一下思路,感覺這個(gè)題應(yīng)該比上一道簡單的多。首先k=1就是順序或者倒敘排列就不說了。如果k = n-1那么穩(wěn)妥的首尾想插入。重點(diǎn)就是中間階段的k怎么實(shí)現(xiàn):因?yàn)榇_定是n個(gè)連續(xù)整數(shù)。所以想保證每一塊的差值一樣還是能做到的??刹豢梢赃@么做:前面插入,到k-1中值的時(shí)候順序開始排列。保持差額是1。感覺可行性還挺高的,我去實(shí)現(xiàn)下試試。
一次ac,性能也不錯(cuò),挺好的。思路就是我上面說的思路,兩邊插入,到達(dá)到的值就順序往下遞增或遞減就ok了。

class Solution {
    public int[] constructArray(int n, int k) {
        int[] res = new int[n];
        int idx = 0;
        int start = 1;
        int end = n;
        boolean flag = true;//下一個(gè)要插入元素。true代表start.false代表end
        while(k-->0) {
            if(flag) {
                res[idx++] = start++;
            }else {
                res[idx++] = end--;             
            }
            flag = !flag;
        }
        if(!flag) {//順序往下
            while(start<=end) res[idx++] = start++;
        }else {//倒敘往上
            while(start<=end) res[idx++] = end--;
        }
        return res;
    }
}

感覺我這個(gè)思路沒啥問題,而且我看了人家給定的答案,我懷疑也是這種做法,只不過人家從多少種不同開始遍歷,最后順序往后順延就行了。我去看看性能第一的代碼,不出意外就這么過了:

class Solution {
    public int[] constructArray(int n, int k) {
        int[] res=new int[n];
        int numk=k+1,numt=1;
        //下標(biāo)段[0,k]中,偶數(shù)填充[1、2、3...]
        for(int i=0;i<=k;i+=2){
            res[i]=numt++;
        }
        //下標(biāo)段[0,k]中,奇數(shù)下標(biāo)填充[k+1,k,k-1...]
        for(int i=1;i<=k;i+=2){
            res[i]=numk--;
        }
        //其余的部分順序填充
        for(int i=k+1;i<n;i++){
            res[i]=i+1;
        }
        return res;
    }
}

精巧的代碼,我是用flag來填充大數(shù)小數(shù)。人家是奇偶數(shù)。這個(gè)題就這樣了。下一題。

最大交換

題目:給定一個(gè)非負(fù)整數(shù),你至多可以交換一次數(shù)字中的任意兩位。返回你能得到的最大值。

示例 1 :
輸入: 2736
輸出: 7236
解釋: 交換數(shù)字2和數(shù)字7。
示例 2 :
輸入: 9973
輸出: 9973
解釋: 不需要交換。
注意:
給定數(shù)字的范圍是 [0, 108]

思路:這個(gè)題就簡單了,首先不存在超時(shí)問題,其次非負(fù)整數(shù)不存在正負(fù)不同分兩種情況的問題,最后大概思路就是第一位不是最大換成最大的,第一位是最大往下判斷。如果這個(gè)數(shù)字已經(jīng)是降序排列了那么就原樣輸出、差不多就這個(gè)思路。我先去實(shí)現(xiàn)下看看。
直接貼代碼:

class Solution {
    public int maximumSwap(int num) {
        char[] arr = String.valueOf(num).toCharArray();
        for(int i = 0;i<arr.length;i++ ) {
            int idx = i;
            char value = arr[i];
            for(int j = i+1;j<arr.length;j++) {
                if(arr[j]>=value && arr[i] != arr[j]) {
                    value = arr[j];
                    idx = j;
                }
            }
            if(idx != i) {
                char temp = arr[i];
                arr[i] = value;
                arr[idx] = temp;
                return Integer.valueOf(new String(arr));
            }
        }
        return num;
    }
}

感覺這個(gè)題的難度可能就是細(xì)節(jié)處理比較繁瑣?反正中間有個(gè)細(xì)節(jié)我坑了兩次:首先如果非當(dāng)前元素,有大于當(dāng)前元素的多個(gè)相同元素,那么用較后的那個(gè)替換。所以這里判斷條件是大于等于。但是如果和當(dāng)前元素一樣是沒必要替換的,所以還要加arr[i]!=arr[j]。就這一點(diǎn)我一開始沒想到所以提交了兩次都是錯(cuò)誤。不過只要注意到還是很容易改的。整體而言這個(gè)題不難。
本篇筆記就記到這里,如果稍微幫到你了記得點(diǎn)個(gè)喜歡點(diǎn)個(gè)關(guān)注。也祝大家工作順順利利~!今日共勉語句:天道酬勤。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容