Go-Python-Java-C-LeetCode 高分解法 - 第 2 週目コレクション

序文

この問題解決策の Go 言語部分はLeetCode-Go に基づいています。
他の部分は私の実践的な学習に基づいています。
個人的な問題解決策の GitHub リンク: LeetCode-Go-Python-Java-C
Go-Python-Java-C-LeetCode High解決方法 - 最初の週の収集
この記事の内容の一部は、オンライン収集と個人的な実践に基づいています。情報に誤りが含まれている場合は、読者の皆様は批判や修正を歓迎します。この記事は学習とコミュニケーションのみを目的としており、商業目的ではありません。

8. 文字列を整数に変換 (atoi)

トピック

文字列を 32 ビット符号付き整数に変換する関数を実装しますmyAtoi(string s)(C/C++ の関数と同様atoi)。

のアルゴリズムはmyAtoi(string s)次のとおりです。

  1. 内容を読み、先頭の空白を無視します。
  2. 次の文字 (文字列の最後にない場合) が'-'または であるかどうかを確認します'+'どちらかであれば、この文字を読み取ってください。これにより、最終結果がそれぞれ陰性か陽性かが決まります。どちらも存在しない場合、結果は肯定的であると仮定します。
  3. 次の非数字文字または入力の終わりに達するまで、次の文字を読み込みます。文字列の残りの部分は無視されます。
  4. これらの数字を整数 (つまり"123" -> 123"0032" -> 32) に変換します。数字が読み取られなかった場合、整数は です0必要に応じて符号を変更します (ステップ 2 から)。
  5. 整数が 32 ビット符号付き整数の範囲外にある場合は[-231, 231 - 1]、整数が範囲内に収まるように整数をクランプします。具体的には、 より小さい整数は231にクランプされ231、 より大きい整数は231 - 1にクランプされる必要があります231 - 1
  6. 最終結果として整数を返します。

注記:

  • スペース文字のみが' '空白文字とみなされます。
  • 先頭の空白以外の文字や数字の後の文字列の残りの部分は無視しないでください。

例 1:

Input: s = "42"
Output: 42
Explanation: The underlined characters are what is read in, the caret is the current reader position.
Step 1: "42" (no characters read because there is no leading whitespace)
         ^
Step 2: "42" (no characters read because there is neither a '-' nor '+')
         ^
Step 3: "42" ("42" is read in)
           ^
The parsed integer is 42.
Since 42 is in the range [-231, 231 - 1], the final result is 42.

例 2:

Input: s = "   -42"
Output: -42
Explanation:
Step 1: "   -42" (leading whitespace is read and ignored)
            ^
Step 2: "   -42" ('-' is read, so the result should be negative)
             ^
Step 3: "   -42" ("42" is read in)
               ^
The parsed integer is -42.
Since -42 is in the range [-231, 231 - 1], the final result is -42.

例 3:

Input: s = "4193 with words"
Output: 4193
Explanation:
Step 1: "4193 with words" (no characters read because there is no leading whitespace)
         ^
Step 2: "4193 with words" (no characters read because there is neither a '-' nor '+')
         ^
Step 3: "4193 with words" ("4193" is read in; reading stops because the next character is a non-digit)
             ^
The parsed integer is 4193.
Since 4193 is in the range [-231, 231 - 1], the final result is 4193.

例 4:

Input: s = "words and 987"
Output: 0
Explanation:
Step 1: "words and 987" (no characters read because there is no leading whitespace)
         ^
Step 2: "words and 987" (no characters read because there is neither a '-' nor '+')
         ^
Step 3: "words and 987" (reading stops immediately because there is a non-digit 'w')
         ^
The parsed integer is 0 because no digits were read.
Since 0 is in the range [-231, 231 - 1], the final result is 0.

例 5:

Input: s = "-91283472332"
Output: -2147483648
Explanation:
Step 1: "-91283472332" (no characters read because there is no leading whitespace)
         ^
Step 2: "-91283472332" ('-' is read, so the result should be negative)
          ^
Step 3: "-91283472332" ("91283472332" is read in)
                     ^
The parsed integer is -91283472332.
Since -91283472332 is less than the lower bound of the range [-231, 231 - 1], the final result is clamped to -231 = -2147483648.

制約:

  • 0 <= s.length <= 200
  • s英字(小文字と大文字)、数字(0-9)、、、で構成されます' ''+'

トピックの一般的な考え方

myAtoi(string s) 関数を実装して、文字列を 32 ビット符号付き整数に変換できるようにしてください (C/C++ の atoi 関数と同様)。

関数 myAtoi(string s) のアルゴリズムは次のとおりです。

  • 文字列を読み取り、不要な先頭のスペースを破棄します。
  • 次の文字 (文字の終わりにまだ達していないと仮定して) が正であるか負であるかを確認し、その文字 (存在する場合) を読み取ります。最終結果が負の数であるか正の数であるかを判断します。どちらも存在しない場合、結果は肯定的なものとみなされます。
  • 次の非数字文字に到達するか、入力の終わりに到達するまで、次の文字を読み取ります。文字列の残りの部分は無視されます。
  • 前の手順で読み取った数値を整数に変換します (つまり、「123」 -> 123、「0032」 -> 32)。数値が読み込まれない場合、整数は 0 になります。必要に応じてシンボルを変更します (ステップ 2 から開始します)。
  • 整数が 32 ビット符号付き整数の範囲 [-231, 231 − 1] を超える場合、この範囲内に収めるために整数を切り捨てる必要があります。具体的には、-231 未満の整数は -231 に固定し、231 − 1 より大きい整数は 231 − 1 に固定する必要があります。
  • 最終結果として整数を返します。

知らせ:

  • この質問の空白文字には、スペース文字「 」のみが含まれます。
  • 先頭のスペースまたは数字の後の文字列の残りを除く文字を無視しないでください。

問題解決のアイデア

  • この質問は単純な質問です。C++この質問では、のatoi関数と同様の関数の実装が必要です。この関数の機能は、文字列型の数値をint型の数値に変換することです。まず、文字列の先頭のスペースを削除し、記録された数値の符号を決定します。先頭の数字は削除する必要があります0最後に、数値を数値型に変換して、int型の上限を超えているかどうかを判断[-2^31, 2^31 - 1]し、上限を超えている場合は、境界を出力する必要があります。つまり-2^31、 または です2^31 - 1

各言語バージョンのソリューションのアイデア:

Go言語

  1. strings.TrimSpace() は先頭のスペースを削除します
  2. strings.Split() は文字列を数値の配列に分割します。
  3. range の場合は文字配列を反復します
  4. strconv.Atoi() は文字を 1 文字ずつ整数に変換します
  5. 整数を配列に追加する
  6. スライス操作では、最初の 100 個の数値の二乗和が求められます。

パイソン

  1. isspace() はスペースを決定し、isdigital() は数字を決定します
  2. int() は文字を整数に強制変換し、try-Except はオーバーフローをキャプチャします。
  3. append() は配列に数値を追加します
  4. itertools.islice() は最初の 100 要素を取得します
  5. sum() は合計を求め、pow() は二乗を求めます

ジャワ

  1. replaceAll() はスペースを置換し、split() は文字列を分割します
  2. Character.isDigit() は数字を決定します
  3. Integer.parseInt() は整数に解析します
  4. ArrayList は整数を格納し、subList() は最初の 100 を取得します
  5. ストリームストリーミング処理、mapToInt().sum()の合計

C++

  1. isspace() はスペースを決定し、 isdigital() は数値を決定します
  2. stoi() は文字を整数に変換します
  3. ベクトルは数値を格納し、resize() はサイズを調整します
  4. 蓄積して合計し、変換して二乗する
  5. 処理のためにベクトルの最初の 100 要素を取得します

コード

行く

func myAtoi(s string) int {
    // 定义最大整数值,是否允许符号,是否允许空白,符号,数字数组
    maxInt, signAllowed, whitespaceAllowed, sign, digits := int64(2<<30), true, true, 1, []int{}
    for _, c := range s {
      // 如果是空格且允许空白,继续
      if c == ' ' && whitespaceAllowed {
         continue
      }
      // 如果允许符号
      if signAllowed {
         // 如果是加号,不再允许符号和空白
         if c == '+' {
            signAllowed = false
            whitespaceAllowed = false
            continue
         } else if c == '-' { // 如果是减号,置符号为-1
            sign = -1
            signAllowed = false
            whitespaceAllowed = false
            continue
         }
      }
      // 如果不是数字,跳出循环
      if c < '0' || c > '9' {
         break
      }
      // 不再允许符号和空白
      whitespaceAllowed, signAllowed = false, false
      // 将字符转换为整数并加入数字数组 
      digits = append(digits, int(c-48))
    }
    // 定义返回值相关变量
    var num, place int64
    place, num = 1, 0
    // 记录最后一个前导0的索引
    lastLeading0Index := -1
    // 找到最后一个前导0
    for i, d := range digits {
       if d == 0 {
          lastLeading0Index = i
       } else {
          break
       }
    }
    // 如果有前导0,去掉前导0
    if lastLeading0Index > -1 {
       digits = digits[lastLeading0Index+1:]
    }
    // 定义正负数最大返回值
    var rtnMax int64
    if sign > 0 {
       rtnMax = maxInt - 1
    } else {
       rtnMax = maxInt
    }
    // 计算数字总位数
    digitsCount := len(digits)
    // 从低位到高位计算数值
    for i := digitsCount - 1; i >= 0; i-- {
       num += int64(digits[i]) * place
       place *= 10
       // 如果超出范围,返回最大值
       if digitsCount-i > 10 || num > rtnMax {
          return int(int64(sign) * rtnMax)
       }
    }
    // 加上符号
    num *= int64(sign)
    return int(num)
}

パイソン

class Solution:
    def myAtoi(self, s: str) -> int:
        max_int = 2**31 - 1
        min_int = -2**31
        sign = 1 # 符号默认为正
        result = 0 # 结果初始化为0
        index = 0
        n = len(s)
        # 去掉前导空格
        while index < n and s[index] == ' ':
            index += 1
        # 判断符号   
        if index < n and s[index] == '+':
            sign = 1
            index += 1
        elif index < n and s[index] == '-':
            sign = -1
            index += 1
        # 将后续数字字符转换为整数累加
        while index < n and s[index].isdigit():
            digit = int(s[index])
            result = result * 10 + digit
            index += 1
            # 每次处理一个数字后检查是否越界
            if result * sign <= min_int:
                return min_int
            if result * sign >= max_int:
                return max_int
        return sign * result

ジャワ

class Solution {
    public int myAtoi(String s) {
        // 定义变量
        long maxInt = Integer.MAX_VALUE; 
        long minInt = Integer.MIN_VALUE;
        boolean signAllowed = true;
        boolean whitespaceAllowed = true;
        int sign = 1;
        List<Integer> digits = new ArrayList<>();

        for(char c : s.toCharArray()) {
            // 处理空格
            if(c == ' ' && whitespaceAllowed) continue;

            // 处理正负号
            if(signAllowed) {
                if(c == '+') {
                    signAllowed = false;
                    whitespaceAllowed = false;
                    continue;
                } else if(c == '-') {
                    sign = -1;
                    signAllowed = false;
                    whitespaceAllowed = false;
                    continue;
                }
            }

            // 非数字则跳出
            if(c < '0' || c > '9') break;

            // 记录数字
            signAllowed = false;
            whitespaceAllowed = false;
            digits.add(c - '0');
        }

        // 处理前导0
        int lastLeading0 = -1;
        for(int i = 0; i < digits.size(); i++) {
            if(digits.get(i) == 0) lastLeading0 = i;
            else break;
        }
        if(lastLeading0 > -1) {
            digits = digits.subList(lastLeading0+1, digits.size());
        }

        // 计算数值
        long num = 0;
        for(int i = digits.size()-1; i >= 0; i--) {
            num += digits.get(i) * Math.pow(10, digits.size()-1-i);
            
            // 处理越界
            if(sign == 1 && num > maxInt) return (int)maxInt;
            if(sign == -1 && -num < minInt) return (int)minInt;
        }
        
        return (int)(sign * num);
    }
}

CPP

#include <iostream>
#include <string>
#include <limits>

class Solution {
public:
    int myAtoi(std::string s) {
        int i = 0;
        int sign = 1;
        int result = 0;

        if (s.empty()) {
            return 0;
        }

        // 跳过空格
        while (i < s.size() && s[i] == ' ') {
            i++;
        }

        // 处理正负号
        if (i < s.size() && (s[i] == '+' || s[i] == '-')) {
            sign = (s[i] == '-') ? -1 : 1;
            i++;
        }

        // 转换数字并检查溢出
        while (i < s.size() && isdigit(s[i])) {
            int digit = s[i] - '0';
            if (result > (std::numeric_limits<int>::max() - digit) / 10) {
                return (sign == 1) ? std::numeric_limits<int>::max() : std::numeric_limits<int>::min();
            }
            result = result * 10 + digit;
            i++;
        }

        return result * sign;
    }
};

各言語バージョンの基本的な知識ポイント:

Go言語

  • strings パッケージ: strings.TrimSpace() は文字列から先頭のスペースを削除でき、strings.Contains() は部分文字列を決定します
  • strconv パッケージ: strconv.Atoi() 文字列から整数へ、strconv.Itoa() 整数から文字列
  • 配列とスライス: 数値は配列に保存され、append() を使用して追加できます。スライス操作は部分文字列を受け取ります。
  • 範囲トラバーサルの場合: 文字列を直接トラバースし、添字またはルーン タイプを通じて文字にアクセスできます。
  • 型変換: Int および int64 型変換が必要です。これは型キャストを使用して実現されます。

パイソン

  • str メソッド: isspace() はスペースを決定し、isdigital() は数値などを決定します。
  • Int 強制変換: 直接 int() は文字列を整数に変換できます
  • Try-Except: Try-Except を使用して整数変換のオーバーフロー例外をキャッチできます。
  • 数学モジュール: pow() 冪等補助メソッドを提供します

ジャワ

  • パッケージ化クラス: Integer、Long、およびその他のボックス化されたクラスは数値範囲定数を提供します
  • ArrayList: 数値を動的に追加できます。subList() は部分文字列を受け取ります。
  • Math クラス: 冪等な数学関数を提供します
  • 型強制: int と long の間の変換を処理する必要があります。

C++

  • ヘッダー ファイル: 数値境界を定義するには imits などが必要です。
  • isdigital() は数字を決定します
  • 文字列処理: substr() は部分文字列などを受け取ります。
  • 例外: 手動による境界判断の代わりに例外を使用できます。
  • 型変換: 静的強制変換または stoi、to_string およびその他の関数

9. 回文番号

トピック

整数が回文であるかどうかを判断します。整数は、後ろから読んでも前から読んでも同じ場合、回文になります。

例 1 :

Input: 121
Output: true

例 2 :

Input: -121
Output: false
Explanation: From left to right, it reads -121. From right to left, it becomes 121-. Therefore it is not a palindrome.

例 3 :

Input: 10
Output: false
Explanation: Reads 01 from right to left. Therefore it is not a palindrome.

フォローアップ:

整数を文字列に変換せずに解決できますか?

トピックの一般的な考え方

整数が回文であるかどうかを判断します。回文番号は、順方向 (左から右) と逆方向 (右から左) で同じ値を読み取る整数です。

問題解決のアイデア

  • 整数が回文であるかどうかを判断します。
  • 素朴な疑問。負の数があることに注意してください。負の数、1 桁、および 10 は回文ではありません。他の整数は回文の規則に従って判断されます。
    Go 言語バージョン:
  1. if を使用して、負の数と末尾の 0 の大文字と小文字を判断し、直接 false を返します。
  2. for ループを使用して x の剰余を継続的に取得し、各数値を取得してスライス arr に保存します。
  3. スライスの長さを決定し、両端から中央まで横断し、それが等しいかどうかを決定します。
  4. 等しくない場合は、直接 false を返し、トラバースの終了時に true を返します。

Python 言語バージョン:

  1. if を使用して負の数を判断し、直接 false を返します。
  2. その後の走査を容易にするために、整数を文字列 s に変換します。
  3. 文字列の長さを求め、文字列の両端から中央までをたどります
  4. 文字が等しいかどうかを判断し、等しくない場合は false を返し、走査が完了すると true を返します。

Java言語バージョン:

  1. 方法 1: Python と同様に、整数を文字列に変換します
  2. 文字列の長さを決定し、両端から中央までたどり、文字が等しいかどうかを判断します。
  3. 方法 2: 整数の除算と剰余を通じて整数を直接演算する
  4. while ループを使用してビットごとに比較し、回文かどうかを判断します。

C++言語バージョン:

  1. if を使用して負の数を判断し、直接 false を返します。
  2. while ループを使用して x の剰余を取得し、各桁をベクトルに格納します。
  3. ベクトルの長さを決定し、両端から中央までたどり、等しいかどうかを決定します。
  4. 文字列に変換して操作することもできます。考え方は上記と同じです
  5. 等しくない場合は、直接 false を返し、トラバースの終了時に true を返します。

コード

行く

// 解法一
func isPalindrome(x int) bool {
    if x < 0 { // 如果x是负数,返回false
       return false
    }
    if x == 0 { // 如果x是0,返回true
       return true
    }
    if x%10 == 0 { // 如果x能被10整除,返回false
       return false
    }
    arr := make([]int, 0, 32) // 创建一个空切片arr
    for x > 0 { // 当x大于0时循环
       arr = append(arr, x%10) // 将x对10取余作为个位数存入arr
       x = x / 10 // x整除10
    }
    sz := len(arr) // 获得arr的长度
    for i, j := 0, sz-1; i <= j; i, j = i+1, j-1 { // 从头尾两边向中间遍历arr
       if arr[i] != arr[j] { // 如果两边的数字不相等
          return false // 返回false
       }
    }
    return true // 遍历完成,说明是回文,返回true
}
// 解法二 数字转字符串
func isPalindrome(x int) bool {
    if x < 0 { // 如果x是负数,返回false
       return false
    }
    if x < 10 { // 单位数都是回文,返回true
       return true
    }
    s := strconv.Itoa(x) // 将x转为字符串
    length := len(s) // 获得字符串长度
    for i := 0; i <= length/2; i++ { // 从两头向中间遍历字符串
       if s[i] != s[length-1-i] { // 如果两边的字符不相等
          return false // 返回false
       }
    }
    return true // 遍历完成,说明是回文,返回true
} 

パイソン

class Solution:
    def isPalindrome(self, x: int) -> bool:
        # 方法一
        if x < 0:
            return False
        if x == 0:
            return True
        if x % 10 == 0:
            return False
        arr = []
        while x > 0:
            arr.append(x % 10)
            x //= 10
        n = len(arr)
        for i in range(n // 2):
            if arr[i] != arr[n - 1 - i]:
                return False
        return True
class Solution:
    def isPalindrome(self, x: int) -> bool:
        # 方法二
        if x < 0:
            return False
        if x < 10:
            return True
        s = str(x)
        n = len(s)
        for i in range(n // 2):
            if s[i] != s[n - 1 - i]:
                return False
        return True 

ジャワ

class Solution {    
  // 解法一:整数转换为字符串
  public boolean isPalindrome(int x) {
    if (x < 0) {
      return false;
    }
    if (x < 10) {
      return true;
    }
    String s = String.valueOf(x);
    int length = s.length();
    for (int i = 0; i <= length / 2; i++) {
      if (s.charAt(i) != s.charAt(length - 1 - i)) {
        return false;
      }
    }
    return true;
  }

}

class Solution {
  // 解法二:直接对整数操作
  public boolean isPalindrome(int x) {
    if (x < 0) {
      return false;
    }
    if (x == 0) {
      return true;
    }
    int div = 1;
    while (x / div >= 10) {
      div *= 10;
    }
    while (x != 0) {
      int left = x / div;
      int right = x % 10;
      if (left != right) {
        return false;
      }
      x = (x % div) / 10;
      div /= 100;
    }
    return true;
  }
}

CPP

class Solution {
public:
    bool isPalindrome(int x) {
        // 方法一
        if(x < 0) return false;
        if(x == 0) return true;
        if(x % 10 == 0) return false;
        vector<int> arr;
        while(x > 0) {
            arr.push_back(x % 10);
            x /= 10;
        }
        int n = arr.size();
        for(int i = 0; i < n / 2; i++) {
            if(arr[i] != arr[n - 1 - i])
                return false;
        }
        return true;

    }
}; 
class Solution {
public:
    bool isPalindrome(int x) {
        // 方法二
        if(x < 0) return false;
        if(x < 10) return true;
        string s = to_string(x);
        int n = s.size();
        for(int i = 0; i < n / 2; i++) {
            if(s[i] != s[n - 1 - i])
                return false;
        }
        return true;

    }
}; 

各言語バージョンに必要な基本的な知識:

Go 言語バージョン:

  1. 条件判定の場合、問題の要件に従って負の数と0の状況を判定します。
  2. 要素を追加するためのスライスと追加の定義
  3. for ループはスライスを走査します
  4. len() はスライスの長さを見つけます
  5. % 剰余演算子は各桁を取得します
  6. /= 演算子は値を除算して代入します

Python 言語バージョン:

  1. if 条件で負の数と 0 が決定される
  2. 整数を文字列に変換する str()
  3. len() は文字列の長さを調べます
  4. 文字列トラバーサルとインデックス アクセス s[i]
  5. //整数除算演算子

Java言語バージョン:

  1. if 条件で負の数と 0 が決定される
  2. String クラスとそのメソッド charAt()
  3. 文字列のトラバースと長さ len
  4. 整数除算演算子 / および剰余演算子 %
  5. while ループ

C++言語バージョン:

  1. if 条件で負の数と 0 が決定される
  2. ベクターコンテナはpush_backとtraversalを追加します
  3. size() はベクトルの長さを求めます
  4. 文字列の_string への変換とトラバーサル
  5. % 剰余演算子は各桁を取得します
  6. /= 演算子は値を除算して代入します

10. 正規表現のマッチング

トピック

入力文字列 s とパターン p を指定して、「.」をサポートする正規表現マッチングを実装します。そして、どこ:

「。」任意の 1 文字と一致します。
' *' 0 個以上の先行要素と一致します。
一致は入力文字列全体 (部分的ではなく) をカバーする必要があります。

例 1:

入力: s = "aa"、p = "a"
出力: false
説明: "a" は文字列 "aa" 全体と一致しません。
例 2:

入力: s = “aa”、p = “a*”
出力: true
説明: '*' は、先行する要素 'a' の 0 個以上を意味します。したがって、「a」を1回繰り返すと「aa」になります。
例 3:

入力: s = "ab"、p = "。"
出力: true
説明: "。
」は、「0 個以上の任意の文字 (.) の (*)」を意味します。

トピックの一般的な考え方

文字列 s と文字パターン p を指定した場合、「.」と「*」をサポートする正規表現マッチングを実装してください。

'.' は任意の 1 文字に一致します
'*' は前の要素の 0 個以上に一致します
いわゆる一致は、文字列の一部ではなく、文字列 s 全体をカバーします。

問題解決のアイデア

Go言語:

  1. 動的計画法を使用して 2 次元配列 f[i][j] を解いて定義し、s の最初の i 文字と p の最初の j 文字が一致するかどうかを表します。
  2. f[0][0] を true に初期化し、2 つの文字列が空の場合に一致することを示します。
  3. 状態転送には 2 層の for ループを使用します。現在の文字が ' ' であり ' ' ではない2 つの状況を考慮してください。
  4. p[j-1]='*' の場合、議論は使用する場合と使用しない場合の 2 つのケースに分かれます。
  5. '*' は使用せず、f[i][j-2] の結果を直接継承します。
  6. '*'を使用してs[i-1]とp[j-2]が一致するかどうかを確認する必要があり、一致する場合はf[i-1][j]を継承します。
  7. '*'でない場合は、s[i-1]とp[j-1]が一致するかどうかを判定し、一致する場合はf[i-1][j-1]を継承します。
  8. 最終結果として f[m][n] を返します

Python 言語:

  1. 動的計画法 + 2 次元配列 f も使用します
  2. f[0][0]をtrueに初期化します
  3. 状態遷移を解決するための二重層 for ループ
  4. p[j-1] が '*' の場合、使用しない場合と使用する場合の 2 つの状況があります。
  5. 継承 f[i][j-2] を使用しない場合は、s[i-1] と p[j-2] が一致することを確認する必要があります。
  6. '*'でない場合は、s[i-1]とp[j-1]が一致すると判断し、f[i-1][j-1]を継承します。
  7. 結果として f[m][n] を返します

Java 言語:
考え方は上記と同じです。

  1. 動的プログラミング、ブール配列 f[i][j] を定義
  2. f[0][0]をtrueに初期化します
  3. 状態転送のための 2 層の for ループ
  4. 」とそうでない状況について話し合う
  5. 「*」は、未使用と使用の 2 つの状況を考慮します。
  6. 非「*」は前の文字が一致するかどうかを決定します
  7. 最終解として f[m][n] を返します

C++ 言語:

  1. 2 次元ベクトルを使用して f を初期化する、動的計画法
  2. f[0][0] は true
  3. 状態転送用の二重層 for ループ
  4. p[j-1]が'*'の場合、未使用と使用に分かれます。
  5. 継承 f[i][j-2] は使用せず、一致を確認するために使用します。
  6. それ以外の場合は、前の文字が一致するかどうかを判断します
  7. 結果として f[m][n] を返します

コード

行く

func isMatch(s string, p string) bool {
    // 定义s和p的长度
    m, n := len(s), len(p)
    // 判断s和p的子串从i和j位置开始是否匹配
    matches := func(i, j int) bool {
        // 如果i为0,说明s为空,返回false
        if i == 0 {
            return false
        }
        // 如果p[j-1]为'.',代表通配符,返回true
        if p[j-1] == '.' {
            return true
        }
        // 否则判断s[i-1]和p[j-1]是否相等
        return s[i-1] == p[j-1]
    }
    // 初始化二维数组f为m+1行n+1列
    f := make([][]bool, m + 1)
    for i := 0; i < len(f); i++ {
        f[i] = make([]bool, n + 1)
    }
    // 边界条件,如果s和p均为空,返回true
    f[0][0] = true
    // 动态规划状态转移
    for i := 0; i <= m; i++ {
        for j := 1; j <= n; j++ {
            // 如果p[j-1]为'*',有两种情况
            if p[j-1] == '*' {
                // 1. 不使用'*',直接继承f[i][j-2]的结果
                f[i][j] = f[i][j] || f[i][j-2]
                // 2. 使用'*',当s[i-1]和p[j-2]匹配时,继承f[i-1][j]的结果
                if matches(i, j - 1) {
                    f[i][j] = f[i][j] || f[i-1][j]
                }
            // 如果s[i-1]和p[j-1]匹配,继承f[i-1][j-1]的结果
            } else if matches(i, j) {
                f[i][j] = f[i][j] || f[i-1][j-1]
            }
        }
    }
    // 返回最终结果f[m][n]
    return f[m][n]
} 

パイソン

class Solution:
    def isMatch(self, s: str, p: str) -> bool:
        m, n = len(s), len(p)
        f = [[False] * (n+1) for _ in range(m+1)]
        f[0][0] = True
        for i in range(m+1):
            for j in range(1, n+1):
                if p[j-1] == '*':
                    f[i][j] |= f[i][j-2]
                    if self.matches(s, p, i, j-1):
                        f[i][j] |= f[i-1][j]
                else:
                    if self.matches(s, p, i, j):
                        f[i][j] |= f[i-1][j-1]
        return f[m][n]
    def matches(self, s, p, i, j):
        if i == 0:
            return False
        if p[j-1] == '.':
            return True
        return s[i-1] == p[j-1]

ジャワ

class Solution {
    public boolean isMatch(String s, String p) {
        int m = s.length();
        int n = p.length();
        boolean[][] f = new boolean[m + 1][n + 1];
        f[0][0] = true;
        for (int i = 0; i <= m; i++) {
            for (int j = 1; j <= n; j++) {
                if (p.charAt(j-1) == '*') {
                    f[i][j] = f[i][j-2];
                    if (matches(s, p, i, j-1)) {
                        f[i][j] = f[i][j] || f[i-1][j];
                    }
                } else {
                    if (matches(s, p, i, j)) {
                        f[i][j] = f[i-1][j-1];
                    }
                }
            }
        }
        return f[m][n];
    }
    public boolean matches(String s, String p, int i, int j) {
        if (i == 0) {
            return false;
        }
        if (p.charAt(j-1) == '.') {
            return true;
        }
        return s.charAt(i-1) == p.charAt(j-1);
    }
}

CPP

class Solution {
public:
    bool isMatch(string s, string p) {
        int m = s.size();
        int n = p.size();
        vector<vector<bool>> f(m + 1, vector<bool>(n + 1, false));
        f[0][0] = true;
        for (int i = 0; i <= m; i++) {
            for (int j = 1; j <= n; j++) {
                if (p[j-1] == '*') {
                    f[i][j] = f[i][j-2];
                    if (matches(s, p, i, j-1)) {
                        f[i][j] = f[i][j] || f[i-1][j];
                    }
                } else {
                    if (matches(s, p, i, j)) {
                        f[i][j] = f[i-1][j-1];
                    }
                }
            }
        }
        return f[m][n];
    }
    bool matches(string s, string p, int i, int j) {
        if (i == 0) {
            return false;
        }
        if (p[j-1] == '.') {
            return true;
        }
        return s[i-1] == p[j-1];
    }
};

Go言語:

  1. 配列/スライスの定義: var arr [n]type、初期化を行い、長さを取得する len
  2. 文字列アクセス: s[i] はインデックスによって文字を取得します
  3. 関数定義: func xxx (パラメータ) 戻り値の型 {}
  4. if 条件判定: if 条件 {} else {}
  5. for ループ: 初期化用; 条件; フォローアップ {}
  6. 論理和:||
  7. 戻り値:直接戻り、複数の値を返すことができます

パイソン:

  1. リスト生成:[[0]* n for _ in range(m)]
  2. 文字列アクセス: s[i]、インデックスは 0 から始まります
  3. 関数定義: def 関数名 (パラメータ):
  4. 条件判定: if 条件: elif: else:
  5. for ループ: コレクション内の for 変数:
  6. 論理和: |
  7. 戻り値: 直接返す

ジャバ:

  1. 配列定義: type [] 配列名 = 新しいタイプ [長さ]
  2. 文字列アクセス: string.charAt(index)
  3. 関数定義:戻り値の型 関数名(パラメータ) {}
  4. 条件判定:if() {} else {}
  5. for ループ: for (初期化; 条件; インクリメント) {}
  6. 論理和:||
  7. 戻り値: 結果を返します。

C++:

  1. ベクトル定義:vector<type> 名 (サイズ)
  2. 文字列アクセス: 文字列[インデックス]
  3. 関数定義:戻り値の型 関数名(パラメータ) {}
  4. 条件判定:if() {} else {}
  5. for ループ: for (初期化; 条件; インクリメント) {}
  6. 論理和:||
  7. 戻り値: 結果を返します。

11. ほとんどの水が入った容器

トピック

n 個の非負の整数 a1、a2、…、an が与えられるとします。ここで、それぞれは座標 (i, ai) の点を表します。線分 i の 2 つの端点が (i, ai) と (i, 0) になるように、n 本の垂直線が描画されます。コンテナに最も多くの水分が含まれるように、x 軸とともにコンテナを形成する 2 つの線を見つけます。

注: コンテナを傾けることはできません。また、n は少なくとも 2 です。

[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-P3DovAkA-1692502410923)(https://s3-lc-upload.s3.amazonaws) .com/uploads/2018 /07/17/question_11.jpg)]

上記の垂直線は配列 [1,8,6,2,5,4,8,3,7] で表されます。この場合、コンテナに入れることができる水の最大面積 (青い部分) は 49 です。

例 1:

Input: [1,8,6,2,5,4,8,3,7]
Output: 49

トピックの一般的な考え方

非負の整数配列 a1、a2、a3、...an を指定すると、各整数は、座標軸の x 位置に建てられた高さ ai の壁を識別します。2 つの壁を選択すると、x 軸によって形成されるコンテナーにはほとんどのものが収容できます水。

問題解決のアイデア

この質問は、ポインタの衝突のアイデアでもあります。ポインターは最初と最後に2つあり、それぞれの移動後に縦と横の積が最大かどうかを判定します。

Goのバージョン

  • 最大領域 max、左ポインタと右ポインタの開始と終了を定義します
  • ループ判定開始<終了
  • 幅幅を終点-始点として計算します
  • 高さを 0 に初期化します
  • 高さ[開始]と高さ[終了]のサイズを決定します。
  • 高さの小さい方の値を採用します
  • ポインタをより低い高さに移動します
  • エリア温度を幅*高さとして計算します
  • 温度と最大値を比較し、最大値を更新します

Pythonのバージョン

  • 最大領域 max を定義し、左右のポインタの開始点と終了点がリストの両端を指すようにします。
  • ループ判定開始<終了
  • 幅幅を終点-始点として計算します
  • 高さを 0 に初期化します
  • 高さ[開始]と高さ[終了]のサイズを決定します。
  • 高さの小さい方の値を採用します
  • ポインタをより低い高さに移動します
  • 面積を幅 * 高さとして計算します。
  • 面積と最大値を比較、最大値を更新

Javaのバージョン

  • 最大領域 max を定義し、左右のポインタの開始点と終了点が配列の両端を指すようにします。
  • ループ判定開始<終了
  • 幅幅を終点-始点として計算します
  • 高さを 0 に初期化します
  • 高さ[開始]と高さ[終了]のサイズを決定します。
  • 高さの小さい方の値を採用します
  • ポインタをより低い高さに移動します
  • エリア温度を幅*高さとして計算します
  • 温度と最大値を比較し、最大値を更新します

C++バージョン

  • 最大領域 max を定義し、左右のポインタの開始点と終了点がベクトルの両端を指すようにします。
  • ループ判定開始<終了
  • 幅幅を終点-始点として計算します
  • 高さを 0 に初期化します
  • 高さ[開始]と高さ[終了]のサイズを決定します。
  • 高さの小さい方の値を採用します
  • ポインタをより低い高さに移動します
  • エリア温度を幅*高さとして計算します
  • 温度と最大値を比較し、最大値を更新します

コード

行く

func maxArea(height []int) int {
    // 初始化最大面积max为0,start为0,end为数组长度-1
    max, start, end := 0, 0, len(height)-1 
    // 当start小于end时循环
    for start < end {
       // 宽度为end-start
       width := end - start 
       // 高初始化为0 
       high := 0
       // 如果start位置的高度小于end位置 
       if height[start] < height[end] {
          // 高为start位置的高度
          high = height[start]
          // start加1
          start++
       } else {
          // 否则高为end位置的高度
          high = height[end]
          // end减1
          end--
       }
       // 临时面积为宽乘高
       temp := width * high
       // 如果临时面积大于最大面积
       if temp > max {
          // 更新最大面积
          max = temp
       }
    }
    // 返回最大面积
    return max
}

パイソン

class Solution:
    def maxArea(self, height: List[int]) -> int:
        # 初始化最大面积为0,左右指针start和end分别指向列表两端
        max_area = 0
        start = 0
        end = len(height) - 1
        while start < end:
            # 计算当前宽度
            width = end - start
            # 初始化高度为0
            high = 0
            if height[start] < height[end]:
                # 如果左指针对应的高度更小,则取左指针高度
                high = height[start]
                # 左指针右移
                start += 1
            else:
                # 否则取右指针高度
                high = height[end]
                # 右指针左移
                end -= 1
            # 计算当前面积   
            area = width * high
            # 如果当前面积大于最大面积,则更新最大面积
            if area > max_area:
                max_area = area
        return max_area

ジャワ

class Solution {
    public int maxArea(int[] height) {
        // 初始化最大面积为0,左右指针start和end分别指向数组两端
        int max = 0, start = 0, end = height.length - 1;
        while(start < end) {
            // 计算当前宽度
            int width = end - start;
            // 初始化高度为0
            int high = 0;
            if(height[start] < height[end]) {
                // 如果左指针对应的高度更小,则取左指针高度
                high = height[start];
                // 左指针右移
                start++;
            } else {
                // 否则取右指针高度
                high = height[end];
                // 右指针左移
                end--;
            }
            // 计算当前面积
            int temp = width * high;
            // 如果当前面积大于最大面积,则更新最大面积
            if(temp > max) {
                max = temp;
            }
        }
        return max;
    }
}

CPP

class Solution {
public:
    int maxArea(vector<int>& height) {
        // 初始化最大面积为0,左右指针start和end分别指向向量两端
        int max = 0, start = 0, end = height.size() - 1;
        while(start < end) {
            // 计算当前宽度
            int width = end - start;
            // 初始化高度为0
            int high = 0;
            if(height[start] < height[end]) {
                // 如果左指针对应的高度更小,则取左指针高度
                high = height[start];
                // 左指针右移
                start++;
            } else {
                // 否则取右指针高度
                high = height[end];
                // 右指针左移
                end--;
            }
            // 计算当前面积
            int temp = width * high;
            // 如果当前面积大于最大面积,则更新最大面积
            if(temp > max) {
                max = temp;
            }
        }
        return max;
    }
};

各言語バージョンに必要な基本的な知識:

Goのバージョン

Go 言語バージョンには次の知識が必要です。

  • 変数宣言 -:=宣言を使用して変数を初期化します
  • 配列 -[]int配列の宣言、len() を使用して配列の長さを取得します。
  • for ループ - for 開始条件、終了条件、ステップ
  • if 条件判定 - if 条件 {} else {}
  • 足し算と引き算 - +、-
  • 乗算 - *
  • より大きい より小さい - >、<
  • 戻り値 - 使用return

Pythonのバージョン

Python バージョンには次の知識が必要です。

  • 変数 - 型を宣言する必要はなく、値を直接割り当てるだけです。
  • List -[]宣言されたリスト len() を使用して長さを取得します
  • while ループ - while 条件:
  • if 条件判定 - if 条件: 、else:
  • 足し算と引き算 - +、-
  • 乗算 - *
  • より大きい より小さい - >、<
  • 戻り値 - 戻り値

Javaのバージョン

Java バージョンには次の知識が必要です。

  • 変数宣言 - 変数のタイプを宣言します。int
  • 配列 -int[]長さを取得するには、宣言配列,.lengthを使用します。
  • for ループまたは while ループ
  • if条件判断 - if() {} else {}
  • 足し算と引き算 - +、-
  • 乗算 - *
  • より大きい より小さい - >、<
  • 戻り値 - 戻り値

C++バージョン

C++ バージョンには次の知識が必要です。

  • 変数宣言 - 変数のタイプを宣言します。int
  • ベクトルコンテナ - ベクトル宣言、.size() は長さを取得します
  • while ループ
  • if条件判断 - if() {} else {}
  • 足し算と引き算 - +、-
  • 乗算 - *
  • より大きい より小さい - >、<
  • 戻り値 - 戻り値

12. 整数からローマ字へ

トピック

Iローマ数字は、VXLCの 7 つの異なる記号で表されますDM

Symbol       Value
I             1
V             5
X             10
L             50
C             100
D             500
M             1000

たとえば、はローマ数字で 1 を 2 つ足した2もののように書きますII12は と書きますがXII、これは
単にですX + II数字は27書きますXXVIIXX + V + II

ローマ数字は通常、左から右に最大から最小まで書かれます。ただし、4 の数字は ではありませんIIII
代わりに、数字の 4 は と書きますIV1 は 5 の前にあるので、それを引いて 4 になります。同じ
原理が、 と書かれる数字の 9 にも当てはまりますIX減算が使用される例は 6 つあります。

  • IV(5)とX(10)の前に配置して4と9を作ることができます。
  • XL(50) と(100)の前に置くとC40 と 90 になります。
  • CD(500) とM(1000)の前に置くと 400 と 900 になります。

整数を与えられた場合、それをローマ数字に変換します。

例 1:

Input: num = 3
Output: "III"

例 2:

Input: num = 4
Output: "IV"

例 3:

Input: num = 9
Output: "IX"

例 4:

Input: num = 58
Output: "LVIII"
Explanation: L = 50, V = 5, III = 3.

例 5:

Input: num = 1994
Output: "MCMXCIV"
Explanation: M = 1000, CM = 900, XC = 90 and IV = 4.

制約:

  • 1 <= num <= 3999

トピックの一般的な考え方

通常、ローマ数字の小さい数字は大きい数字の右側にあります。ただし、特殊な場合があり、たとえば 4 は IIII ではなく IV と表記されます。
数字 1 は数字 5 の左側にあり、大きな数字5 から数字 1 を引いた値、つまり値 4 を表します。同様に、数字の 9 は IX と表されます。この特別ルールは、次の 6 つの状況にのみ適用されます。

  • I を V(5) と X(10) の左側に配置して、4 と 9 を表すことができます。
  • X を L(50) と C(100) の左側に配置して、40 と 90 を表すことができます。
  • C を D(500) と M(1000) の左側に配置して、400 と 900 を表すことができます。

整数を与えられた場合、それをローマ数字に変換します。入力が 1 ~ 3999 の範囲内であることを確認してください。

問題解決のアイデア

  • 質問の意味に応じて、大きい数を優先し、貪欲なアルゴリズムを使用して問題を解決します。1~3999の範囲のローマ数字を大きい順から小さい順に配列に入れ、最初から最後まで選択して整数をローマ数字に変換します。

Go 言語バージョン:

  1. ローマ数字のすべての組み合わせを含む整数配列値と文字列配列シンボルを定義します
  2. 初期化結果文字列 res は空で、インデックス i は 0
  3. for ループを使用して、num が 0 でない場合にループします。
  4. ループ内でif判定を使用し、現在値の値がnumより大きい場合、iをインクリメントしてスキップします。
  5. numから現在の値の値を減算します
  6. 対応するシンボル内の文字列を res に接続します。
  7. 最後にres文字列を結果として返します

Python 言語バージョン:

  1. ローマ数字のすべての組み合わせを含む、値リストの値とシンボルリストのシンボルを定義します。
  2. 初期化結果文字列 res は空で、インデックス i は 0
  3. while ループを使用して、num が 0 より大きい場合にループします。
  4. ループ内でif判定を使用し、現在値の値がnumより大きい場合、iをインクリメントしてスキップします。
  5. numから現在の値の値を減算します
  6. 対応するシンボル内の文字列を res に接続します。
  7. 最後にres文字列を結果として返します

Java言語バージョン:

  1. ローマ数字のすべての組み合わせを含む整数配列値と文字列配列シンボルを定義します
  2. 初期化結果文字列 res は空で、インデックス i は 0
  3. while ループを使用して、num が 0 より大きい場合にループします。
  4. ループ内でif判定を使用し、現在値の値がnumより大きい場合、iをインクリメントしてスキップします。
  5. numから現在の値の値を減算します
  6. 対応するシンボル内の文字列を res に接続します。
  7. 最後にres文字列を結果として返します

C++言語バージョン:

  1. ローマ数字のすべての組み合わせを含む整数配列値と文字列配列シンボルを定義します
  2. 初期化結果文字列 res は空で、インデックス i は 0
  3. while ループを使用して、num が 0 より大きい場合にループします。
  4. ループ内でif判定を使用し、現在値の値がnumより大きい場合、iをインクリメントしてスキップします。
  5. numから現在の値の値を減算します
  6. 対応するシンボル内の文字列を res に接続します。
  7. 最後にres文字列を結果として返します

コード

行く

func intToRoman(num int) string {
    values := []int{1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1} // 定义一个整数数组,包含罗马数字的基本值
    symbols := []string{"M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"} // 定义一个字符串数组,包含对应的罗马符号
    res, i := "", 0 // res为返回的罗马数字字符串,i为values和symbols的索引
    for num != 0 { // 当num不为0时循环
        for values[i] > num { // 如果当前values中的值大于num
            i++ // i增加1
        }
        num -= values[i] // 从num中减去当前values中的值
        res += symbols[i] // 在res中加上对应的罗马符号
    }
    return res // 返回组成的罗马数字字符串
}

パイソン

class Solution:
    def intToRoman(self, num: int) -> str:
        values = [1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1] # 定义值列表
        symbols = ["M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"] # 符号列表
        res = ""
        i = 0 # 结果字符串和索引
        while num > 0: # 当num大于0时循环
            while values[i] > num: # 如果当前值大于num
                i += 1 # 索引加1
            num -= values[i] # 从num中减去当前值
            res += symbols[i] # 在结果中添加对应的符号
        return res # 返回组成的罗马数字字符串

ジャワ

class Solution {
    public String intToRoman(int num) {
        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"}; // 定义字符串数组,包含罗马符号
        String res = "";
        int i = 0; // 结果字符串res,以及values和symbols的索引i
        while(num > 0) { // 当num大于0时循环
            while(values[i] > num) { // 如果当前values中的值大于num
                i++; // i增加1
            }
            num -= values[i]; // 从num中减去当前values中的值
            res += symbols[i]; // 在res中添加对应的罗马符号
        }
        return res; // 返回组成的罗马数字字符串
    }
}

CPP

class Solution {
public:
    string intToRoman(int num) {
        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"}; // 定义字符串数组,包含罗马符号
        string res;
        int i = 0; // 结果字符串res,以及values和symbols的索引i
        while(num > 0) { // 当num大于0时循环
            while(values[i] > num) { // 如果当前values中的值大于num
                i++; // i增加1
            }
            num -= values[i]; // 从num中减去当前values中的值
            res += symbols[i]; // 在res中添加对应的罗马符号
        }
        return res; // 返回组成的罗马数字字符串
    }
};

Go 言語バージョン:

  • int 型: Go 言語の整数型。整数を表すために使用されます。
  • 文字列型: Go言語の文字列型。
  • []int と[]string: は、整数配列と文字列配列を定義します。
  • for ループ: Go 言語の基本的なループ構造。
  • if 条件判定: Go言語の条件判定構造。
  • += 演算子: 文字列または整数の連結代入演算子。
  • 関数定義と戻り値:Go言語で関数を定義する形式と戻り値の方法。

Python 言語バージョン:

  • int型:Pythonにおける整数型。
  • str型:Pythonにおける文字列型。
  • list: Python のリスト。配列に相当します。
  • while ループ: Python の基本的なループ構造。
  • if 条件判定: Python の条件判定構造。
  • += 演算子: 文字列連結代入演算子。
  • def は関数、戻り値を定義します: Python で関数と戻り値を定義する方法。

Java言語バージョン:

  • int型:Javaにおける整数型。
  • 文字列型: Java の String クラス。
  • int[] とString[]: は、整数配列と文字列配列を定義します。
  • while ループ: Java のループ構造。
  • if 条件判定: Java の条件判定構造。
  • += 演算子: 文字列連結代入演算子。
  • メソッド定義、戻り値の返し:Javaでメソッドと戻り値を定義する方法。

C++言語バージョン:

  • int型:C++における整数型。
  • 文字列型: C++ の文字列クラス。
  • int[] とstring[]: は、整数配列と文字列配列を定義します。
  • while ループ: C++ ループ構造。
  • if 条件判定: C++ の条件判定構造体。
  • += 演算子: 文字列連結代入演算子。
  • 関数定義、戻り値の返し: C++ で関数と戻り値を定義する方法。

13. ローマ字から整数へ

トピック

Iローマ数字は、VXLCの 7 つの異なる記号で表されますDM

Symbol       Value
I             1
V             5
X             10
L             50
C             100
D             500
M             1000

たとえば、2 はIIローマ数字で書きますが、1 を 2 つ足しただけです。12 は、 と書きます。XIIこれは
単にX+ですII数字の 27 は と書きますXXVIIこれはXX++ですVII

ローマ数字は通常、左から右に最大から最小まで書かれます。ただし、4 の数字は ではありませんIIII
代わりに、数字の 4 は と書きますIV1 は 5 の前にあるので、それを引いて 4 になります。同じ
原理が、 と書かれる数字の 9 にも当てはまりますIX減算が使用される例は 6 つあります。

  • IV(5)とX(10)の前に配置して4と9を作ることができます。
  • XL(50) と(100)の前に置くとC40 と 90 になります。
  • CD(500) とM(1000)の前に置くと 400 と 900 になります。

与えられたローマ数字を整数に変換します。入力は 1 ~ 3999 の範囲内であることが保証されます。

例 1 :

Input: "III"
Output: 3

例 2 :

Input: "IV"
Output: 4

例 3 :

Input: "IX"
Output: 9

例 4 :

Input: "LVIII"
Output: 58
Explanation: L = 50, V= 5, III = 3.

例 5 :

Input: "MCMXCIV"
Output: 1994
Explanation: M = 1000, CM = 900, XC = 90 and IV = 4.

トピックの一般的な考え方

ローマ数字には、I、V、X、L、C、D、M の 7 文字が含まれます。


字符          数值
I             1
V             5
X             10
L             50
C             100
D             500
M             1000

たとえば、ローマ数字の 2 は 1 が 2 つ並んで II と表記され、12 は XII (X + II) と表記されます。27はXXVIIと書きます、つまりXX+V+IIです。

通常、ローマ数字の小さい数字は大きい数字の右側にあります。ただし、特殊な場合があり、たとえば 4 は IIII ではなく IV と表記されます。
数字 1 は数字 5 の左側にあり、大きな数字5 から数字 1 を引いた値、つまり値 4 を表します。同様に、数字の 9 は IX と表されます。この特別ルールは、次の 6 つの状況にのみ適用されます。

  • I を V(5) と X(10) の左側に配置して、4 と 9 を表すことができます。
  • X を L(50) と C(100) の左側に配置して、40 と 90 を表すことができます。- C を D(500) および M(1000) の左側に配置して、400 および 900 を表すことができます。

与えられたローマ数字を整数に変換します。入力が 1 ~ 3999 の範囲内であることを確認してください。

問題解決のアイデア

  • 与えられたローマ数字を整数に変換します。入力が 1 ~ 3999 の範囲内であることを確認してください。
  • 素朴な疑問。問題内のローマ数字の文字値に従って、ローマ数字に対応する 10 進数を計算するだけです。

Go 言語バージョン:

  1. 文字から整数へのマップ マッピングを作成する
  2. 文字列が空かどうかを判断し、空の場合は 0 を返します。
  3. 0に初期化されるnum、lastNum、total変数を定義します。
  4. 文字列を後ろから前にトラバースします
  5. 現在の文字を取得し、マップ内で対応する値を見つけます。
  6. 現在の値と以前の値の関係を確認します。以前の値より小さい場合は、現在の値を減算し、そうでない場合は、現在の値を加算します。
  7. lastNum を現在の値に更新します
  8. トラバーサルの最後に合計結果が返されます。

Python 言語バージョン:

  1. 文字から整数への dict 辞書を作成する
  2. 文字列が空かどうかを判断し、空の場合は 0 を返します。
  3. 0 に初期化される num、last_num、total 変数を定義します。
  4. len-1 から 0 までの範囲で文字列を逆順に走査します。
  5. 現在の文字を取得し、辞書内で対応する値を見つけます。
  6. 現在の値と以前の値の関係を確認します。以前の値より小さい場合は、現在の値を減算し、そうでない場合は、現在の値を加算します。
  7. last_num を現在の値に更新します
  8. トラバーサルの最後に合計結果が返されます。

Java言語バージョン:

  1. 文字から整数へのマップ マッピングを作成する
  2. 文字列が空かどうかを判断し、空の場合は 0 を返します。
  3. 0に初期化されるnum、lastNum、total変数を定義します。
  4. 文字列を逆順に走査する、i-実装
  5. 現在の文字を取得し、マップ内で対応する値を見つけます。
  6. 現在の値と以前の値の関係を確認します。以前の値より小さい場合は、現在の値を減算し、そうでない場合は、現在の値を加算します。
  7. lastNum を現在の値に更新します
  8. トラバーサルの最後に合計結果が返されます。

C++言語バージョン:

  1. 文字から整数へのマップ マッピングを作成する
  2. 文字列が空かどうかを判断し、空の場合は 0 を返します。
  3. 0に初期化されるnum、lastNum、total変数を定義します。
  4. 文字列を逆順に走査する、i-実装
  5. 現在の文字を取得し、マップ内で対応する値を見つけます。
  6. 現在の値と以前の値の関係を確認します。以前の値より小さい場合は、現在の値を減算し、そうでない場合は、現在の値を加算します。
  7. lastNum を現在の値に更新します
  8. トラバーサルの最後に合計結果が返されます。

コード

行く

// 定义一个map,映射罗马数字字符到整数值
var roman = map[string]int{ 
    "I": 1,
    "V": 5, 
    "X": 10,
    "L": 50,
    "C": 100,
    "D": 500,
    "M": 1000,
}
// 将罗马数字字符串转换为整数的函数
func romanToInt(s string) int {
    // 如果传入空字符串,直接返回0
    if s == "" { 
       return 0
    }
    // 定义num为当前数字值,lastint为上一个数字值,total为结果
    num, lastint, total := 0, 0, 0
    // 从字符串末尾向前遍历
    for i := 0; i < len(s); i++ {
       // 获取当前字符 
       char := s[len(s)-(i+1) : len(s)-i]
       // 在map中找当前字符对应的数字值 
       num = roman[char]
       // 如果当前数字小于上一个数字,则减去当前数字
       if num < lastint {
          total = total - num
       } else {
           // 否则加上当前数字
          total = total + num
       }
       // 更新lastint为当前数字值
       lastint = num
    }
    // 返回最终结果
    return total
}

パイソン

class Solution:
    def romanToInt(self, s: str) -> int:
        
        # 定义一个字典,映射罗马数字字符到整数值
        roman = {'I': 1, 'V': 5, 'X': 10, 'L': 50, 'C': 100, 'D': 500, 'M': 1000}
        
        # 如果传入空字符串,直接返回0
        if not s:
            return 0
        
        # 定义当前数字、上一个数字和结果变量        
        num, last_num, total = 0, 0, 0
        
        # 从字符串末尾向前遍历
        for i in range(len(s)-1, -1, -1):
            
            # 获取当前字符
            char = s[i]
            
            # 在字典中找当前字符对应的数字
            num = roman[char]
            
            # 如果当前数字小于上一个数字,则减去当前数字
            if num < last_num:
                total -= num
            else:
                # 否则加上当前数字
                total += num
                
            # 更新last_num为当前数字
            last_num = num
        
        return total
        

ジャワ

class Solution {
    public int romanToInt(String s) {
        // 定义一个Map,映射罗马数字字符到整数值
        Map<Character, Integer> roman = new HashMap<>();
        roman.put('I', 1);
        roman.put('V', 5);
        roman.put('X', 10);
        roman.put('L', 50);
        roman.put('C', 100);
        roman.put('D', 500);
        roman.put('M', 1000);

        // 如果传入空字符串,直接返回0
        if (s.isEmpty()) {
            return 0;
        }
        
        // 初始化lastNum为0
        int num, lastNum = 0, total = 0;

        // 从字符串末尾向前遍历
        for (int i = s.length() - 1; i >= 0; i--) {

            // 获取当前字符
            char c = s.charAt(i);

            // 在map中找当前字符对应的数字
            num = roman.get(c);

            // 如果当前数字小于上一个数字,则减去当前数字
            if (num < lastNum) {
                total -= num; 
            } else {
                // 否则加上当前数字
                total += num;
            }

            // 更新lastNum为当前数字
            lastNum = num;
        }
        
        // 返回最终结果
        return total;
    }
}

CPP

class Solution {
public:
    int romanToInt(string s) {
        
        // 定义一个map,映射罗马数字字符到整数值
        unordered_map<char, int> roman = {
   
   {'I', 1}, {'V', 5}, {'X', 10}, {'L', 50}, 
                                         {'C', 100}, {'D', 500}, {'M', 1000}}; 
        
        // 如果传入空字符串,直接返回0
        if (s.empty()) {
            return 0; 
        }
        
        // 定义当前数字、上一个数字和结果变量
        int num, lastNum = 0, total = 0;
        
        // 从字符串末尾向前遍历
        for (int i = s.length() - 1; i >= 0; i--) {
            
            // 获取当前字符
            char c = s[i];
            
            // 在map中找当前字符对应的数字值
            num = roman[c];
            
            // 如果当前数字小于上一个数字,则减去当前数字
            if (num < lastNum) {
                total -= num;
            } else {
                // 否则加上当前数字
                total += num;
            }
            
            // 更新lastNum为当前数字
            lastNum = num;
        }
        
        return total;
    }
};

Go 言語バージョン:

  • マップ: Go 言語では、マップは文字と整数の間のマッピング関係を確立するために使用できるキーと値のペアのコレクションです。
  • len関数:文字列の長さを取得できます。
  • Slice:s[start:end] は文字列の部分文字列を抽出できます。
  • if条件判定とelse分岐。
  • 複数の変数を定義します: num、lastint、total := 0、0、0。
  • for ループは文字列を反復処理します。
    -文字列連結: char := s[len(s)-(i+1) : len(s)-i]。

Python 言語バージョン:

  • Dictionary dict: Python の辞書は、文字と整数の間のマッピング関係を確立できます。
  • len関数:文字列の長さを取得できます。
    -添字インデックス:s[i] は文字列内の文字を取得します。
  • if条件判定とelse分岐。
  • 複数の変数を定義します: num、last_num、total = 0、0、0。
  • for ループは文字列を走査し、range 関数はインデックスを生成します。
  • 減算演算: range(len(s)-1, -1, -1)。

Java言語バージョン:

  • マップコレクション: キーと値のペアのマッピング関係を確立できます。
  • isEmpty は文字列が空かどうかを判断します。
  • charAt は、文字列内の指定された位置にある文字を取得します。
  • HashMap は Map コレクションを作成します。
  • if条件判定とelse分岐。
  • for ループは文字列 i を走査し、逆の順序を実装します。
  • length は文字列の長さを取得します。

C++言語バージョン:

  • unowned_map マッピング コレクション。文字と整数のマッピングを確立できます。
  • empty は文字列が空かどうかを決定します。
  • []ベクター要素にアクセスします。
  • if条件判定とelse分岐。
  • 複数の変数を定義します: int num、lastNum = 0、total = 0。
  • for ループは文字列 i を走査し、逆の順序を実装します。
  • length 関数は文字列の長さを取得します。

14. 最長の共通プレフィックス

トピック

文字列の配列の中から最も長い共通プレフィックス文字列を検索する関数を作成します。

共通のプレフィックスがない場合は、空の文字列「」を返します。

例 1 :

Input: strs = ["flower","flow","flight"]
Output: "fl"

例 2 :

Input: strs = ["dog","racecar","car"]
Output: ""
Explanation: There is no common prefix among the input strings.

制約:

  • 1 <= strs.length <= 200
  • 0 <= strs[i].length <= 200
  • strs[i] は英小文字のみで構成されます。

トピックの一般的な考え方

文字列の配列内で最も長い共通プレフィックスを検索する関数を作成します。

共通のプレフィックスが存在しない場合は、空の文字列 "" が返されます。

問題解決のアイデア

  • 文字列の長さに応じて strs を昇順に並べ替え、strs 内の最小の文字列の長さ minLen を見つけます。
  • 文字列内の最小長の文字と他の文字列を 1 つずつ比較し、等しくない場合は commonPrefix を返し、等しくない場合は commonPrefix に文字を追加します。

Goのバージョン

  1. 最初の文字列をプレフィックスとして設定します
  2. 残りの文字列を反復処理します
  3. プレフィックスを文字ごとに比較し、等しくない場合はプレフィックスの長さを減らします。
  4. プレフィックスが空になるか、すべての文字列と一致するまで手順 3 を繰り返します。
  5. プレフィックスを返すには、
    主に文字列のトラバーサルとスライス操作を使用して、プレフィックスを徐々に短くします。

Pythonのバージョン

  1. 最初の文字列はプレフィックスです
  2. 残りの文字列をループします
  3. find メソッドを使用して、プレフィックスで始まるかどうかを確認します
  4. 一致しない場合は、プレフィックス長を短くしてください
  5. プレフィックスが空になるか、すべての文字列と一致するまで、手順 3 と 4 を繰り返します。
  6. プレフィックスを返すには、
    find メソッドとスライス操作を使用してプレフィックスを決定し、変更します。

Javaのバージョン

  1. 最初の文字列はプレフィックスです
  2. 残りの文字列をループします
  3. IndexOf を使用してプレフィックスで始まるかどうかを判断します
  4. 一致しない場合は、プレフィックス長を短くしてください
  5. プレフィックスが空になるか、すべての文字列と一致するまで、手順 3 と 4 を繰り返します。
  6. プレフィックスを返す場合
    も、indexOf メソッドと substring メソッドを使用してサブストリングを決定し、取得します。

C++バージョン

  1. 最初の文字列はプレフィックスです
  2. 残りの文字列をループします
  3. find メソッドを使用して、プレフィックスで始まるかどうかを確認します
  4. 一致しない場合は、プレフィックス長を短くしてください
  5. プレフィックスが空になるか、すべての文字列と一致するまで、手順 3 と 4 を繰り返します。
  6. プレフィックスを返すに
    は、find メソッドと substr メソッドを利用して部分文字列を決定し、取得します。

コード

行く

func longestCommonPrefix(strs []string) string {
    prefix := strs[0]

    for i := 1; i < len(strs); i++ {
        for j := 0; j < len(prefix); j++ {
            if len(strs[i]) <= j || strs[i][j] != prefix[j] {
                prefix = prefix[0:j]
                break
            }
        }
    }

    return prefix
}

パイソン

class Solution:
    def longestCommonPrefix(self, strs: List[str]) -> str:
        if not strs: return ""
        prefix = strs[0]
        for i in range(1, len(strs)):
            while strs[i].find(prefix) != 0:
                prefix = prefix[:len(prefix)-1]
                if not prefix: return ""
        return prefix

ジャワ

class Solution {
    public String longestCommonPrefix(String[] strs) {
        if (strs.length == 0) return "";
        String prefix = strs[0];
        for (int i = 1; i < strs.length; i++) {
            while (strs[i].indexOf(prefix) != 0) {
                prefix = prefix.substring(0, prefix.length() - 1);
                if (prefix.isEmpty()) return "";
            }       
        }
        return prefix;
    }
}

CPP

class Solution {
public:
    string longestCommonPrefix(vector<string>& strs) {
        if (strs.empty()) return "";
        string prefix = strs[0];
        for (int i = 1; i < strs.size(); i++) {
            while (strs[i].find(prefix) != 0) {
                prefix = prefix.substr(0, prefix.size()-1);
                if (prefix.empty()) return "";
            }
        }
        return prefix;
    }
};

各バージョンに必要な基本知識:

Goのバージョン

  • strings パッケージ: strings パッケージは、Contains、Index などの文字列操作関連の関数を提供します。
  • 文字列トラバーサル: for ループを通じて文字列のバイトをトラバースできます。
  • 文字列のスライス: 開始位置と終了位置を指定することで部分文字列を取得できます [i:j]

Pythonのバージョン

  • str 型: Python の組み込み文字列型
  • find メソッド: 文字列内で部分文字列が出現する位置を検索し、最初に一致した位置のインデックスを返します。存在しない場合は、-1 を返します。
  • スライス操作:開始位置と終了位置を指定して部分文字列を取得可能 [i:j]

Javaのバージョン

  • String クラス: String は不変の文字列を表し、インデックス アクセス文字や部分文字列の取得などのメソッドを持ちます。
  • IndexOf メソッド: 文字列内で部分文字列が出現する位置を検索し、最初に一致した位置のインデックスを返します。存在しない場合は、-1 を返します。
  • substring メソッド: 指定された範囲の文字列の部分文字列を取得します。

C++バージョン

  • String クラス: string は文字列オブジェクトを表し、トラバース、個々の文字へのアクセス、部分文字列の取得などの操作をサポートします。
  • find メソッド: 文字列内で部分文字列が最初に出現する位置を検索します。存在しない場合は、string::npos を返します。
  • substr メソッド: 部分文字列内の指定された範囲の文字を取得します。

おすすめ

転載: blog.csdn.net/qq_42531954/article/details/132390148