1. 程式人生 > 其它 >day10 1208 翻硬幣(遞推)

day10 1208 翻硬幣(遞推)

技術標籤:演算法刷題java字串遊戲演算法

1208. 翻硬幣

小明正在玩一個“翻硬幣”的遊戲。

桌上放著排成一排的若干硬幣。我們用* 表示正面,用o表示反面(是小寫字母,不是零)。

比如,可能情形是:**oo***oooo

如果同時翻轉左邊的兩個硬幣,則變為:oooo***oooo

現在小明的問題是:如果已知了初始狀態和要達到的目標狀態,每次只能同時翻轉相鄰的兩個硬幣,那麼對特定的局面,最少要翻動多少次呢?

我們約定:把翻動相鄰的兩個硬幣叫做一步操作。

輸入格式
兩行等長的字串,分別表示初始狀態和要達到的目標狀態。

輸出格式
一個整數,表示最小操作步數

資料範圍
輸入字串的長度均不超過100。

資料保證答案一定有解。

輸入樣例1:
**********
o****o****

輸出樣例1:
5
輸入樣例2:
*o**o***o***
*o***o**o***

輸出樣例2:
1

思路

除第一與最後兩枚硬幣外,想要變動一個硬幣有2個選擇 ,那就是翻動這個硬幣和他的左邊或右邊那枚硬幣,如此一來 若我們認準改變狀態只翻動該硬幣和它右邊的硬幣,即可傻瓜式操作,如果當前硬幣與目標狀態不一致就翻動該硬幣和它右邊的硬幣。
PS:由於題目保證有解,所以無需考慮最後一個硬幣,若不保證有解,那麼最後一個幣在操作一番後,狀態與目標狀態是否一致就成了有無解的標準。

細節解釋

我們可以這樣思考這個題目,我們如何使翻硬幣次數最少就能達到最終目的呢?


不妨假設我們隨便翻,如果這樣,我們每改變一個位置的硬幣,都會影響周圍兩個硬幣的狀態,且只能影響其中一個(要麼前面的,要麼後面的),這樣的話我們即使使用暴力列舉完成也無法保證其次數最少,怎麼辦讓它次數最少呢?

很簡單,我們每翻一個硬幣就把他的狀態固定下來,即我每翻一個硬幣,就保證前面的硬幣和目標硬幣狀態一樣了,這樣的話次數就最少了…

仔細思考上面的思路,並不難理解,想明白上面的大體思路我們再來看怎樣去翻,假設第二個位置和目標狀態不同,我怎麼去翻,我一定要去翻第二個硬幣來使得它與目標狀態相同,也可以理解為如果當前判斷的硬幣狀態與目標硬幣狀態不同,我就翻當前狀態的硬幣,和下一個硬幣,為什麼要這樣呢,為啥第二個位置不同就不能翻第二個硬幣和第一個硬幣呢?

我前面說了,一定要保證翻過的硬幣狀態就和目標狀態相同,也就是說,我在判斷第一個硬幣狀態的時候就已經將第一個硬幣狀態確定下來了,第二個硬幣無論如何不能影響第一個硬幣,即我們在翻任何一個與目標硬幣不相同的硬幣時,只能翻下一個硬幣,而不能翻前面的硬幣,這個思路應該還是不難理解的…

import java.util.Scanner;

public class Main {
     public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        char[] source = scanner.nextLine().toCharArray();
        char[] target = scanner.nextLine().toCharArray();
        int res = 0;
        //由於題目保證有解,故最後一枚硬幣經過前面的操作後一定是相同的了,不用比較了,
         //故i<source.length-1即可,否則寫成i<source.length,則turn(source,i+1)時,i+1將出現下標越界
        for(int i = 0;i < source.length - 1;i++){
            if(source[i] != target[i]){//當前硬幣與目標狀態不同,翻轉它和它右邊的硬幣
                turn(source,i);
                turn(source,i+1);
                res++;//操作次數加一
            }
        }
        System.out.println(res);
    }
    
    //用於翻轉硬幣
    private static void turn(char[] source, int i) {
        if(source[i] =='*') source[i] = 'o';
        else source[i] = '*';
    }
}

在這裡插入圖片描述