「アルゴリズムシリーズ」に貪欲に

導入

  バックトラッキング アルゴリズムのコアがバックトラッキング テンプレートである場合、貪欲アルゴリズムのコアは、大域最適を達成するための局所最適という1 つの文になります。この文を満たすことができる問題は、貪欲なアルゴリズムによって解決できます。実際のところ、貪欲アルゴリズムには決まった書き方はなく、動的計画の問題には特定のテンプレートの影が見られると思いますが、貪欲ではなく、さまざまな書き方があります。張無忌が太極拳を学ぶように、学びながら忘れ、心の言葉を思い出すとコツが見え、コツがなくても勝つコツがある

理論的根拠

  貪欲アルゴリズム(貪欲アルゴリズム)とは、問題を解決する際に、常に現時点で最善の選択をすれば問題の答えが得られるという意味です。貪欲アルゴリズムはトピック内の条件を徹底的に探索する必要があり、固定パターンはなく、貪欲アルゴリズムを解くには、ある程度の直感と経験が必要です。貪欲なアルゴリズムでは、すべての問題に対して全体的に最適な解決策が得られるわけではありません。貪欲なアルゴリズムを使用して解決できる問題には、貪欲な選択の特性があります。貪欲な選択の特性には厳密に数学的証明が必要です。貪欲アルゴリズムを使用して解決できる問題には、後遺症があってはなりません。つまり、特定の状態の前のプロセスは将来の状態に影響を与えず、現在の状態にのみ関連します。つまり、大域的最適値は次から推測できます。局所最適。
  前回の紹介と同様に、貪欲アルゴリズムのコード実装には決まった書き方はなく、私が行った質問の中にはあらゆる書き方がありますが、強いて言うなら、それをより頻繁に使用する必要があります。貪欲なアルゴリズムの問​​題は、考えるのが難しいことがよくあります。つまり、それを行うために貪欲なアルゴリズムを使用する必要があるかどうかはわかりませんが、一般的に書くのは難しくありませんここで注意すべき点の 1 つは、質問によっては、局所最適から大域最適を推定できないことです。現時点では、貪欲アルゴリズムの使用は適切ではありません。貪欲アルゴリズムの罠にはまらないようにしてください。時間をおいてから別の解決策を選択してください。

問題解決の経験

  • 貪欲なアルゴリズムの核心は、全体的な最適化を達成するための局所的な最適化です。
  • 貪欲なアルゴリズムを使用すると、局所的な最適値から全体的な最高の品質を導き出すことができます。
  • 貪欲なアルゴリズムの記述方法では、トピック内の条件を十分に調査する必要があり、固定されたパターンはありません。
  • 固定された手がないため、貪欲なアルゴリズムの問​​題には一定の直感と経験が必要です。
  • 貪欲アルゴリズムの問​​題は、考えるのが難しいことがよくあります。つまり、問題を解決するために貪欲アルゴリズムを使用する必要があるかどうかはわかりませんが、記述方法は一般に難しくありません。
  • 局所的な最適化が必ずしも全体的な最適化につながるとは限らないため、貪欲なアルゴリズムの罠にはまらないようにしてください。

アルゴリズムのトピック

12. 整数からローマ数字へ

ここに画像の説明を挿入
トピック分析: 解決するための貪欲なアルゴリズム。毎回より大きな数値を選択します。
コードは以下のように表示されます。

/**
 * 贪心算法
 */
class Solution {
    int[] values = {1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1};
    String[] symbols = {"M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"};

    public String intToRoman(int num) {
        StringBuffer roman = new StringBuffer();
        // 从1000依次选择至1
        for (int i = 0; i < values.length; i++) {
            int value = values[i];
            String symbol = symbols[i];
            while (num >= value) {
                num -= value;
                roman.append(symbol);
            }
            if (num == 0) {
                break;
            }
        }
        return roman.toString();
    }
}

45. ジャンピングゲームⅡ

ここに画像の説明を挿入
トピック分析: この質問では、パス パス内の最も長い位置のインデックスを見つけ、それを次の離陸位置として使用する必要があります。
コードは以下のように表示されます。

/**
 * 贪心算法
 */
class Solution {
    public int jump(int[] nums) {
        if (nums == null || nums.length == 0 || nums.length == 1) {
            return 0;
        }
        //记录跳跃的次数
        int count=0;
        //当前的覆盖最大区域
        int curDistance = 0;
        //最大的覆盖区域
        int maxDistance = 0;
        for (int i = 0; i < nums.length; i++) {
            //在可覆盖区域内更新最大的覆盖区域
            maxDistance = Math.max(maxDistance,i+nums[i]);
            //说明当前一步,再跳一步就到达了末尾
            if (maxDistance>=nums.length-1){
                count++;
                break;
            }
            //走到当前覆盖的最大区域时,更新下一步可达的最大区域
            if (i==curDistance){
                curDistance = maxDistance;
                count++;
            }
        }
        return count;
    }
} 

55. ジャンプゲーム

ここに画像の説明を挿入
トピック分析: 貪欲なアルゴリズム。各ステップには最大の数が必要です。
コードは以下のように表示されます。

/**
 * 贪心算法
 */
class Solution {
    public boolean canJump(int[] nums) {
        int index = 0;
        while (true) {
            int temp = helper(nums, index);
            // 如果下标没变,说明己到最远处,结束循环
            if (index == temp) {
                break;
            } else {
                // 更新下标
                index = temp;
            }
        }

        if (index == nums.length - 1) {
            return true;
        } else {
            return false;
        }

    }

    // 选取每一步最大值的下标
    public int helper(int[] nums, int index) {
        int max = nums[index];
        int len = nums.length;
        for (int i = index; i < i + nums[index]; i++) {
            // 到底直接返回
            if (i == len - 1) {
                return i;
            }
            // 更新下标
            if (i + nums[i] >= index + max) {
                max = nums[i];
                index = i;
            }
        }
        return index;
    }
}

122. 株を売買するのに最適な時期 II

ここに画像の説明を挿入
トピック分析:当日が前日より大きい限り、売ることができます 注:トピックによると、同日に売った後に買うことができます。
コードは以下のように表示されます。

/**
 * 贪心算法
 */
class Solution {
    public int maxProfit(int[] prices) {
        int res = 0;
        for (int i = 1; i < prices.length; i++) {
            if (prices[i] > prices[i - 1]) {
                res += prices[i] - prices[i - 1];
            }
        }
        return res;
    }
}

134. ガソリンスタンド

ここに画像の説明を挿入
トピック分析: 貪欲なアルゴリズム。各ガソリン スタンドを最初から最後まで横断し、最終的にそのガソリン スタンドを出発点として 1 週間運転できるかどうかを確認します。
コードは以下のように表示されます。

/**
 * 贪心算法
 */
class Solution {
    public int canCompleteCircuit(int[] gas, int[] cost) {
        // 剩余油量
        int total = 0;
        // 假设起始点
        int index = 0;
        // 从假设起始点的剩余油量之和
        int sum = 0;
        for (int i = 0; i < gas.length; i++) {
            int temp = gas[i] - cost[i];
            // 计算所有剩余油量
            total += temp;
            // 计算从假设起始点的剩余油量
            sum += temp;
            // 如果当前 sum 值为负数,则到目前为此的加油站点都不适合做起点
            if (sum < 0) {
                index = i + 1;
                sum = 0;
            }
        }
        // 如果gas[] < cost[] 总量,则一定不可行驶一周,直接返回 -1
        if (total < 0) {
            return -1;
        }
        return index;
    }
}

135. お菓子を配る

ここに画像の説明を挿入
トピック分析: 2 つのトラバース、最初は左から右へ、左側が右側よりも大きく、右側のキャンディーの数が 1 つ増加します。2 回目は右から左へ、右側が左側より大きく、左側は同じスコアとは言えないので、最大 (右側の数値 + 1、現在の数値) を選択します。キャンディーの量は同じでなければなりません。
コードは以下のように表示されます。

/**
 * 贪心算法 
 */
class Solution {

    public int candy(int[] ratings) {
        
        int[] candyVec = new int[ratings.length];
        candyVec[0] = 1;

        // 默认糖数都为1,从左往右遍历
        for (int i = 1; i < ratings.length; i++) {
            if (ratings[i] > ratings[i - 1]) {
                candyVec[i] = candyVec[i - 1] + 1;
            } else {
                candyVec[i] = 1;
            }
        }

        // 从右往左遍历
        for (int i = ratings.length - 2; i >= 0; i--) {
            if (ratings[i] > ratings[i + 1]) {
                candyVec[i] = Math.max(candyVec[i], candyVec[i + 1] + 1);
            }
        }

        int res = 0;
        for (int s : candyVec) {
            res += s;
        }
        return res;
    }
}

179. 最大数

ここに画像の説明を挿入
トピック分析: s1 + s2 および s2 + s1 を比較する並べ替え方法をカスタマイズします。
コードは以下のように表示されます。

/**
 * 贪心算法
 */
class Solution {
    public String largestNumber(int[] nums) {
        PriorityQueue<String> heap = new PriorityQueue<>((x, y) -> (y + x).compareTo(x + y));
        for(int x: nums) heap.offer(String.valueOf(x));
        String res = "";
        while(heap.size() > 0) res += heap.poll();
        if(res.charAt(0) == '0') return "0";
        return res;
    }
}

ホームページに戻る

Leetcode 500 以上の質問を磨くことについての感想

「アルゴリズムシリーズ」の動的計画法

おすすめ

転載: blog.csdn.net/qq_22136439/article/details/126683850