国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

算法50:動態(tài)規(guī)劃專練(力扣514題:自由之路-----4種寫法)

這篇具有很好參考價值的文章主要介紹了算法50:動態(tài)規(guī)劃專練(力扣514題:自由之路-----4種寫法)。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

題目: 力扣514 : 自由之路??. - 力扣(LeetCode)

題目的詳細描述,直接打開力扣看就是了,下面說一下我對題目的理解:

事例1:

輸入: ring = "godding", key = "gd"
輸出: 4.

1. ring的第一個字符默認是指向12點方向的,這一點很重要

2. key的第一個字符為g,而ring中首字符和末尾字符都為g。因此,必然存在選擇首字符的g還是末尾字符g的問題。

3. 即使ring中第一個字符為g,也還存在存在順時針旋轉和逆時針旋轉的問題。(當然,當前案例比較極端,如果第一個字符不為g,理解起來更合適)

4. 這一題要求的是旋轉的最小步數(shù)。因此,最終的值必然是獲取最小值的。

5. 那么整體串起來分析:

????????ring = "godding", key = "gd"

? ? ? ?

字符 g o d d i n g
下標 0 1 2 3 4 5 6

a1. 如果ring的第一個g旋轉,順時針步數(shù)為0;逆時針步數(shù)為7;算上最終確認的1步,因此就? ? ? ? ? ? ? ?是在 1 和 8中選取最小值,選取1

a2. 接著a1繼續(xù)分析,既然key的第一個字符已經(jīng)確定了。那么key的第二個字符d又該選擇? ? ? ? ? ? ? ? ? ?了。我們到底是用下標為2的d呢,還是使用下標為3的d呢?

選擇1: 下標為2的d,從a1的g順時針旋轉只需要2步,逆時針旋轉需要5步,。算上確認的1步,就是在3和6中選取最小值,選取3

選擇2: 下標為3的d, 從a1的g順時針旋轉只需要3步,逆時針旋轉需要4步。算上確認的1步,就是在4和5中選取最小值. 選取 4

如果g使用的是ring中第一個字符,針對以上2種選擇,最好的選擇就是使用下標為2的d,順時針旋轉2步,即3步。? 那么,總的代價就是 1 + 3 = 4。

開頭,我們就說過,ring中有開頭和結尾都存在g,因此存在選擇的問題。

b1. 如果我們使用ring中下標為6的g最為key的開頭。順時針旋轉需要1步,逆時針旋轉需要6步,算上最終確認的1步,就是2步和7步。選取最小值2.

b2. 接著b1繼續(xù)分析,既然key的第一個字符已經(jīng)確定了。那么key的第二個字符d又該選擇? ? ? ? 了。我們到底是用下標為2的d呢,還是使用下標為3的d呢?

選擇1: 下標為2的d,從b1的g順時針旋轉只需要4步,逆時針旋轉需要3步,。算上確認的1步,就是在5和4中選取最小值,選取4

選擇2: 下標為3的d, 從b1的g順時針旋轉只需要3步,逆時針旋轉需要4步。算上確認的1步,就是在4和5中選取最小值. 選取4

如果g使用的是ring中最后一個字符,針對以上2種選擇,最好都為4。? 那么,總的代價就是 2 + 4 = 6。

最終,如果以ring中第一個g作為旋轉選擇,最小的步數(shù)為4;? 以ring中最后一個g作為旋轉選擇,那么最小步數(shù)為6;? 因此,當前案例最小步數(shù)為 Math.min(4, 6).

遞歸代碼:

package 刷題.第三天;


import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 力扣514: 自由之路
 * https://leetcode.cn/problems/freedom-trail/
 */
public class C2_FreeDomTtail_leet514_遞歸 {

    //遞歸版本
    public int findRotateSteps(String ring, String key) {

        if (ring == null || ring.length() == 0 || key == null || key.length() == 0) {
            return 0;
        }

        char[] source = ring.toCharArray();
        char[] target = key.toCharArray();

        //記錄下每個字符的位置,有可能存在重復值的情況
        HashMap<Character, List> map = new HashMap<Character, List>();
        for (int i = 0; i < ring.length(); i++) {
            if (map.containsKey(source[i])) {
                //放入下標的位置
                map.get(source[i]).add(i);
            }
            else {
                List list = new ArrayList();
                list.add(i);
                map.put(source[i], list);
            }
        }

        return process(map, source, 0, target, 0);
    }


    public int process (Map<Character, List> map,
                        char[] source, int sourceStartIndex,
                        char[] target, int targetIndex) {
        if (targetIndex == target.length) {
            return 0;
        }

        List<Integer> ops = map.get(target[targetIndex]);
        int minStep = Integer.MAX_VALUE;
        for (int i = 0; i < ops.size(); i++) {
            //從sourceStartIndex 到 ops.get(i) 最下步數(shù); +1是確認按鈕耗費的1步
            int step = getMinSteps(sourceStartIndex, ops.get(i), source.length) + 1;

            //深度優(yōu)先遍歷; 此時source的的開始位置為 ops.get(i)
            minStep = Math.min(minStep, step + process(map, source, ops.get(i), target, targetIndex + 1));
        }

        return minStep;
    }

    //獲取從最小長度
    public int getMinSteps(int start, int end, int size)
    {
        //如果start < end, 則是順時針; 反之, 逆時針
        int step1 = Math.abs(start - end);

        //如果step1是順時針,那么step則是逆時針; 反之,順時針
        int step2 = size - step1;

        return Math.min(step1, step2);
    }

    public static void main(String[] args) {
        C2_FreeDomTtail_leet514_遞歸 ss = new C2_FreeDomTtail_leet514_遞歸();
        String source = "godding";
        String target = "gd";

        System.out.println(ss.findRotateSteps(source, target));
    }
}

測試結果:

算法50:動態(tài)規(guī)劃專練(力扣514題:自由之路-----4種寫法),算法,算法,動態(tài)規(guī)劃,leetcode

超時是好事情,說明整體邏輯大概率是沒有問題的。超時,說明遞歸計算的次數(shù)有問題。上方的分析過程中,a2和b2 都是針對d進行邏輯判斷的,明顯存在重復的過程。那么,就需要在遞歸的基礎之上添加緩存了,俗稱記憶化搜索。

我之前在說動態(tài)規(guī)劃的時候就說過,如果表結構依賴不嚴格,或者說即使依賴嚴格表結構,但是沒有優(yōu)化的空間。? 遞歸 + 緩存 ==?動態(tài)規(guī)劃。

遞歸+緩存版本:

package 刷題.第三天;


import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 力扣514: 自由之路
 * https://leetcode.cn/problems/freedom-trail/
 */
public class C2_FreeDomTtail_leet514_遞歸_緩存 {

    //遞歸 + 緩存
    public int findRotateSteps(String ring, String key) {

        if (ring == null || ring.length() == 0 || key == null || key.length() == 0) {
            return 0;
        }

        char[] source = ring.toCharArray();
        char[] target = key.toCharArray();

        //記錄下每個字符的位置,有可能存在重復值的情況
        HashMap<Character, List> map = new HashMap<Character, List>();
        for (int i = 0; i < ring.length(); i++) {
            if (map.containsKey(source[i])) {
                //放入下標的位置
                map.get(source[i]).add(i);
            }
            else {
                List list = new ArrayList();
                list.add(i);
                map.put(source[i], list);
            }
        }

        int[][] dp = new int[source.length][target.length];
        for (int i = 0; i < source.length; i++) {
            for (int j = 0; j < target.length; j++) {
                //代表沒算過
                dp[i][j] = -1;
            }
        }

        return process(map, source, 0, target, 0, dp);
    }


    public int process (Map<Character, List> map,
                        char[] source, int sourceStartIndex,
                        char[] target, int targetIndex,
                        int[][] dp) {

        if (targetIndex == target.length) {
            return 0;
        }

        //緩存
        if (dp[sourceStartIndex][targetIndex] != -1) {
            return dp[sourceStartIndex][targetIndex];
        }

        List<Integer> ops = map.get(target[targetIndex]);
        int minStep = Integer.MAX_VALUE;
        for (int i = 0; i < ops.size(); i++) {
            //從sourceStartIndex 到 ops.get(i) 最下步數(shù); +1是確認按鈕耗費的1步
            int step = getMinSteps(sourceStartIndex, ops.get(i), source.length) + 1;

            //深度優(yōu)先遍歷; 此時source的的開始位置為 ops.get(i)
            minStep = Math.min(minStep, step + process(map, source, ops.get(i), target, targetIndex + 1, dp));

            dp[sourceStartIndex][targetIndex] = minStep;
        }

        return minStep;
    }

    //獲取從最小長度
    public int getMinSteps(int start, int end, int size)
    {
        //如果start < end, 則是順時針; 反之, 逆時針
        int step1 = Math.abs(start - end);

        //如果step1是順時針,那么step則是逆時針; 反之,順時針
        int step2 = size - step1;

        return Math.min(step1, step2);
    }

    public static void main(String[] args) {
        C2_FreeDomTtail_leet514_遞歸_緩存 ss = new C2_FreeDomTtail_leet514_遞歸_緩存();
        String source = "godding";
        String target = "gd";

        System.out.println(ss.findRotateSteps(source, target));
    }
}

測試結果:

算法50:動態(tài)規(guī)劃專練(力扣514題:自由之路-----4種寫法),算法,算法,動態(tài)規(guī)劃,leetcode

84%的勝率,8毫秒,已經(jīng)相當優(yōu)秀了。其實,這就是最優(yōu)解

第三版本:純動態(tài)規(guī)劃

動態(tài)規(guī)劃,那就需要分析遞歸的邏輯了。下面以ring作為行,以key作為列

第一步:

0 (g) 1 (d)
0 (g)

下標0的g:?

順時針:1步

逆時針:8步

選取1步

1 (o)
2?(d)
3 (d)
4 (i)
5 (n)
6 (g)

下標6的g :

順時針:2步

逆時針:7步

選取2步

第二步:

0 (g) 1 (d)
0 (g)

下標0的g: 1步

1 (o)
2?(d)

下標為2的d:

從下標為0的g過來,

順時針2步,逆時針5步,

算上確認的1步,

就是3步和6步,選取小值,即3步

從下標為6的g過來,

順時針3步,逆時針4步,

算上確認的1步,

就是4步和5步,選取小值,即4步

最終值就是:

1+3 和 2 +4選取小的。即4步

1是下標為0的g耗費的1步

2是下標為6的g耗費的2步

3 (d)

下標為3的d:

從下標為0的g過來,

順時針3步,逆時針4步,

算上確認的1步,

就是4步和5步,選取小值,即4步

從下標為6的g過來,

順時針4步,逆時針3步,

算上確認的1步,

就是5步和4步,選取小值,即4步

最終值就是:

1+4 和 2 +4選取小的。即5步

1是下標為0的g耗費的1步

2是下標為6的g耗費的2步

4 (i)
5 (n)
6 (g) 下標6的g : 2步

因此,最終最小的步數(shù)就是當key遍歷完最后一個字符得到,即 1 + 3 = 4步;

純動態(tài)規(guī)劃

package 刷題.第三天;


import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 力扣514: 自由之路
 * https://leetcode.cn/problems/freedom-trail/
 */
public class C2_FreeDomTtail_leet514_動態(tài)規(guī)劃 {

    //純動態(tài)規(guī)劃
    public int findRotateSteps(String ring, String key) {

        if (ring == null || ring.length() == 0 || key == null || key.length() == 0) {
            return 0;
        }

        char[] source = ring.toCharArray();
        char[] target = key.toCharArray();

        //記錄下每個字符的位置,有可能存在重復值的情況
        HashMap<Character, List> map = new HashMap<Character, List>();
        for (int i = 0; i < ring.length(); i++) {
            if (map.containsKey(source[i])) {
                //放入下標的位置
                map.get(source[i]).add(i);
            }
            else {
                List list = new ArrayList();
                list.add(i);
                map.put(source[i], list);
            }
        }

        int[][] dp = new int[source.length][target.length + 1];
        //最終返回的最小值
        int finalMinStep = Integer.MAX_VALUE;
        //第一列
        List<Integer> ops = map.get(target[0]);
        for (int index : ops) {
            dp[index][0] = getMinSteps(0, index, source.length) + 1;
            //如果要拼接的key只有一個字符,直接獲取最小值即可
            finalMinStep = Math.min(finalMinStep,  dp[index][0]);
        }

        //如果要拼接的字符長度超過1,那么finalMinStep的值需要
        //等到 target的最后一列才能確定
        if (target.length > 1) {
            finalMinStep = Integer.MAX_VALUE;
        }
        //列遍歷,從第二列開始往后遍歷
        for (int i = 1; i < target.length ; i++)
        {
            //當前列對應的行信息
            List<Integer> ops2 = map.get(target[i]);
            //當前列前一列對應的行信息
            List<Integer> ops3 = map.get(target[i-1]);

            for (int j : ops2)  //結束
            {
                //j行i列的默認最小值
                int minStep = Integer.MAX_VALUE;
                for(int m : ops3) //開始
                {
                    //從m行到j行的步數(shù)
                    int curStep = getMinSteps(m, j, source.length) + 1;
                    //dp[m][i-1] : 從0到m累計步數(shù)
                    //dp[j][i-1] + curStep : 代表從0行到j行累計步數(shù)
                    int steps = dp[m][i-1] + curStep;
                    //更新j行i列的最小值
                    minStep = Math.min(minStep, steps);
                    dp[j][i] = minStep;
                }

                //要拼接字符串的最后一個字符,也就是說可以
                //已經(jīng)全部拼接完了
                if (i == target.length - 1) {
                    finalMinStep = Math.min(finalMinStep, dp[j][i]);
                }
            }
        }

        return finalMinStep;
    }


    //獲取從最小長度
    public int getMinSteps(int start, int end, int size)
    {
        //如果start < end, 則是順時針; 反之, 逆時針
        int step1 = Math.abs(start - end);

        //如果step1是順時針,那么step則是逆時針; 反之,順時針
        int step2 = size - step1;

        return Math.min(step1, step2);
    }

    public static void main(String[] args) {
        C2_FreeDomTtail_leet514_動態(tài)規(guī)劃 ss = new C2_FreeDomTtail_leet514_動態(tài)規(guī)劃();
        /*String source = "godding";
        String target = "gd";*/

        String source = "eh";
        String target = "h";

        System.out.println(ss.findRotateSteps(source, target));
    }
}

測試結果:

算法50:動態(tài)規(guī)劃專練(力扣514題:自由之路-----4種寫法),算法,算法,動態(tài)規(guī)劃,leetcode

10毫秒,76%勝率,也還行。

第四種解法,即官方解法。因為勝率沒有我寫的兩個版本的高,我就不說了。

官方代碼勝率:

算法50:動態(tài)規(guī)劃專練(力扣514題:自由之路-----4種寫法),算法,算法,動態(tài)規(guī)劃,leetcode文章來源地址http://www.zghlxwxcb.cn/news/detail-852469.html

到了這里,關于算法50:動態(tài)規(guī)劃專練(力扣514題:自由之路-----4種寫法)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。如若轉載,請注明出處: 如若內(nèi)容造成侵權/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領支付寶紅包贊助服務器費用

相關文章

  • 動態(tài)規(guī)劃專練( 279.完全平方數(shù))

    給你一個整數(shù) n ,返回 和為 n 的完全平方數(shù)的最少數(shù)量 。 完全平方數(shù) 是一個整數(shù),其值等于另一個整數(shù)的平方;換句話說,其值等于一個整數(shù)自乘的積。例如, 1 、 4 、 9 和 16 都是完全平方數(shù),而 3 和 11 不是。 示例 1: 示例 2: 提示: 1 = n = 104 題解: 本題也是一個完全

    2024年04月16日
    瀏覽(16)
  • 【算法 - 動態(tài)規(guī)劃】力扣 691. 貼紙拼詞

    上一篇文章中的兩道較為簡單的題目都是通過 暴力遞歸 逐步修改成為 動態(tài)規(guī)劃 ,并使用了嚴格的 dp表依賴 ,相信小伙伴對此有了初步的認識。 本文我們來練習一道 LeetCode 中 Hard 級別,不使用嚴格的表依賴的題目。 力扣691. 貼紙拼詞 我們有 n 種不同的貼紙。每個貼紙上都

    2024年02月21日
    瀏覽(18)
  • 《算法通關之路》-chapter9動態(tài)規(guī)劃

    《算法通關之路》學習筆記,記錄一下自己的刷題過程,詳細的內(nèi)容請大家購買作者的書籍查閱。 爬樓梯 力扣第70題 假設你正在爬樓梯。需要 n 階你才能到達樓頂。 每次你可以爬 1 或 2 個臺階。你有多少種不同的方法可以爬到樓頂呢? 打家劫舍 力扣第198題 你是一個專業(yè)的

    2024年02月07日
    瀏覽(25)
  • 力扣刷題-動態(tài)規(guī)劃算法3:完全背包問題

    力扣刷題-動態(tài)規(guī)劃算法3:完全背包問題

    問題描述: 1)有N件物品和一個最多能背重量為W的背包。第i件物品的重量是weight[i],得到的價值是value[i] 。 2) 每件物品都有無限個(也就是可以放入背包多次) (比0-1背包多出的條件) 3) 求解將哪些物品裝入背包里物品價值總和最大。 求解步驟: 1)首先遍歷物品,然

    2023年04月13日
    瀏覽(137)
  • 【算法】力扣【動態(tài)規(guī)劃,LCS】1143. 最長公共子序列

    1143. 最長公共子序列 本文是對 LCS 這一 動態(tài)規(guī)劃 模型的整理,以力扣平臺上的算法題1143:最長公共子序列為模板題進行解析。 該題目要求計算兩個字符串的最長公共子序列(Longest Common Subsequence,簡稱LCS)的長度。字符串的子序列是指在不改變字符順序的情況下,通過刪去

    2024年01月17日
    瀏覽(27)
  • 【算法思考記錄】動態(tài)規(guī)劃入門!力扣2606. 找到最大開銷的子字符串【Python3、動態(tài)規(guī)劃】

    原題鏈接 動態(tài)規(guī)劃(Dynamic Programming,簡稱 DP)是一種通過將原問題分解為相互重疊的子問題并只解決一次的方法來解決問題的算法優(yōu)化技術。動態(tài)規(guī)劃通常用于優(yōu)化遞歸問題,通過存儲子問題的解來避免重復計算,從而顯著提高算法的效率。 動態(tài)規(guī)劃的基本思想是將原問題

    2024年02月03日
    瀏覽(26)
  • 【leetcode刷題之路】劍指Offer(4)——分治+排序算法+動態(tài)規(guī)劃

    8 分治算法 8.1 【遞歸】劍指 Offer 07 - 重建二叉樹 https://leetcode.cn/problems/zhong-jian-er-cha-shu-lcof/ ??前序遍歷是根左右,中序遍歷是左根右,這也就意味著前序遍歷的第一個節(jié)點是整棵樹的根節(jié)點,順著這個節(jié)點找到它在中序遍歷中的位置,即為in_root,那么in_root左邊的都在左子

    2024年02月11日
    瀏覽(23)
  • 【算法】力扣【動態(tài)規(guī)劃、狀態(tài)機】309. 買賣股票的最佳時機含冷凍期

    309. 買賣股票的最佳時機含冷凍期 本文介紹解決力扣平臺上第309號問題——“買賣股票的最佳時機含冷凍期”的算法。這是一個中等難度的問題,其核心是通過設計一個算法來計算在給定的股票價格數(shù)組 prices 下,能夠獲取的最大利潤。股票價格數(shù)組 prices 中的每個元素 pric

    2024年01月18日
    瀏覽(26)
  • 【leetcode刷題之路】初級算法(2)——鏈表+樹+排序和搜索+動態(tài)規(guī)劃

    3.1 【鏈表】刪除鏈表中的節(jié)點 https://leetcode.cn/problems/delete-node-in-a-linked-list/ 給出的就是要刪除的那個節(jié)點,直接前后移動就行了。 3.2 【雙指針】刪除鏈表的倒數(shù)第 N 個結點 https://leetcode.cn/problems/remove-nth-node-from-end-of-list/ 利用雙指針left和right,首先讓right遍歷n個節(jié)點,再讓兩

    2024年02月10日
    瀏覽(42)
  • 力扣算法刷題Day39|動態(tài)規(guī)劃:不同路徑 I&II

    力扣題目:#62.不同路徑 刷題時長:參考題解后10min 解題方法:動規(guī) 復雜度分析 時間O(m*n) 空間O(m*n) 問題總結 初始化二維數(shù)組的python語法:i 對應 m,j 對應n 二維遍歷順序,從上到下從左到右通過兩層for循環(huán)實現(xiàn),其中startindex應為1 本題收獲 動規(guī)思路 確定dp數(shù)組及下標的含義

    2024年02月12日
    瀏覽(19)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領取紅包,優(yōu)惠每天領

二維碼1

領取紅包

二維碼2

領紅包