1. 程式人生 > >C# 算法題系列(二) 各位相加、整數反轉、回文數、羅馬數字轉整數

C# 算法題系列(二) 各位相加、整數反轉、回文數、羅馬數字轉整數

獲取值 字符數組 ron 時間復雜度 bject problem 大量 sharp 計算

各位相加

給定一個非負整數 num,反復將各個位上的數字相加,直到結果為一位數。

示例:

輸入: 38
輸出: 2 
解釋: 各位相加的過程為:3 + 8 = 11, 1 + 1 = 2。 由於 2 是一位數,所以返回 2

進階:
你可以不使用循環或者遞歸,且在 O(1) 時間復雜度內解決這個問題嗎?

題目地址 https://leetcode-cn.com/problems/add-digits/

代碼模板

public class Solution {
    public int AddDigits(int num) {

    }
}

測試數據

輸入 1
輸出 1

輸入 10
輸出 
1 輸入 38 輸出 2 輸入 199 輸出 1 輸入 8888 輸出 5

筆者的方法:

使用了while循環,除一次計算一次,原始數和各位數和同時變化。時間在70ms內。

        public static int Csum(int num)
        {
            if (num < 10)       //小於10的數直接返回
                return num;
            int shi = 0;        //記錄個位數相加
            while (num > 0)
            {
                
if (num >= 10) { shi += num % 10; num = num / 10; } else if (num < 10) { shi += num; num = num / 10; } if (shi >= 10) shi = shi % 10
+ shi / 10;    //超過10的個位數重新變化 } return shi; }

方法二 棄九驗算法

同樣在 60-70ms

public class Solution {
    public int AddDigits(int num) {
        if(num==0)
            return 0;
        if(num%9==0)
            return 9;
        return num%9;
    }
}


整數反轉

給出一個 32 位的有符號整數,你需要將這個整數中每位上的數字進行反轉。

示例 1:

輸入: 123
輸出: 321

示例 2:

輸入: -123
輸出: -321

示例 3:

輸入: 120
輸出: 21

註意:

假設我們的環境只能存儲得下 32 位的有符號整數,則其數值範圍為 [?231, 231 ? 1]。請根據這個假設,如果反轉後整數溢出那麽就返回 0

題目地址 https://leetcode-cn.com/problems/reverse-integer/

代碼模板

public class Solution {
    public int Reverse(int x) {
        
    }
}

筆者方法 68ms左右

   public class Solution
    {
        public int Reverse(int x)
        {

            int num = 0;
            while (x != 0)
            {
                int i = x % 10;
                x = x / 10;
                //C# int32 範圍 [-2147483647~2147483647]
                if (num > int.MaxValue / 10 )
                    return 0;
                if (num < int.MinValue / 10)
                    return 0;

                num = num * 10 + i;
            }
            return num;
        }
    }

回文數

判斷一個整數是否是回文數。回文數是指正序(從左向右)和倒序(從右向左)讀都是一樣的整數。

題目地址:https://leetcode-cn.com/problems/palindrome-number

示例 1:

輸入: 121
輸出: true

示例 2:

輸入: -121
輸出: false
解釋: 從左向右讀, 為 -121 。 從右向左讀, 為 121- 。因此它不是一個回文數。

示例 3:

輸入: 10
輸出: false
解釋: 從右向左讀, 為 01 。因此它不是一個回文數。

進階:

你能不將整數轉為字符串來解決這個問題嗎?

代碼模板

public class Solution {
    public bool IsPalindrome(int x) {
        
    }
}

筆者的代碼

運行時間在120ms左右,筆者的思路是:如果一個數字的反序還是等於這個數,那麽這個數就是回文數。

以下代碼無法解決反序後可能溢出,可以利用上一題的代碼進行溢出檢查。

當然,一個int類型的數,如果是回文,那麽他的反序肯定不會溢出,反之其反序發生溢出則肯定不是回文數。

    public class Solution
    {
        public bool IsPalindrome(int x)
        {
            if (x < 0) return false;
            int xx = x;
            int num = 0;  //x的反序
            while (xx != 0)    //求反序
            {
                int i = xx % 10;
                xx = xx / 10;
                num = num * 10 + i;
            }
            if (x == num)       //如果x的反序num==x,那麽這個數字是回文數
                return true;

            else
                return false;

        }
    }

加try-catch,耗時增加 10~20ms

            try { 
            while (xx != 0)
            {
                int i = xx % 10;
                xx = xx / 10;
                num = num * 10 + i;
            }
            }
            catch
            {
                return false;
            }

官方這道題給出了示例代碼,耗時120ms左右,思路是只反序一半,反序後的原始數、反序一半的數進行比較,也就不用檢查溢出。

public class Solution {
    public bool IsPalindrome(int x) {
        // 特殊情況:
        // 如上所述,當 x < 0 時,x 不是回文數。
        // 同樣地,如果數字的最後一位是 0,為了使該數字為回文,
        // 則其第一位數字也應該是 0
        // 只有 0 滿足這一屬性
        if(x < 0 || (x % 10 == 0 && x != 0)) {
            return false;
        }

        int revertedNumber = 0;
        while(x > revertedNumber) {
            revertedNumber = revertedNumber * 10 + x % 10;
            x /= 10;
        }

        // 當數字長度為奇數時,我們可以通過 revertedNumber/10 去除處於中位的數字。
        // 例如,當輸入為 12321 時,在 while 循環的末尾我們可以得到 x = 12,revertedNumber = 123,
        // 由於處於中位的數字不影響回文(它總是與自己相等),所以我們可以簡單地將其去除。
        return x == revertedNumber || x == revertedNumber/10;
    }
}

別人用字符串方式進行判斷(雖然題目說不能用string),耗時150-180ms,不太穩定

    public class Solution
    {
        public bool IsPalindrome(int x)
        {
            string str = x.ToString();
            for (int i = 0; i < str.Length / 2; ++i)
            {
                if (str[i] != str[str.Length - 1 - i])
                {
                    return false;
                }
            }
            return true;
        }
    }

羅馬數字轉整數

羅馬數字包含以下七種字符: IVXLCDM

題目地址 https://leetcode-cn.com/problems/roman-to-integer/submissions/

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

例如, 羅馬數字 2 寫做 II ,即為兩個並列的 1。12 寫做 XII ,即為 X + II 。 27 寫做 XXVII, 即為 XX + V + II

通常情況下,羅馬數字中小的數字在大的數字的右邊。但也存在特例,例如 4 不寫做 IIII,而是 IV。數字 1 在數字 5 的左邊,所表示的數等於大數 5 減小數 1 得到的數值 4 。同樣地,數字 9 表示為 IX。這個特殊的規則只適用於以下六種情況:

  • I 可以放在 V (5) 和 X (10) 的左邊,來表示 4 和 9。
  • X 可以放在 L (50) 和 C (100) 的左邊,來表示 40 和 90。
  • C 可以放在 D (500) 和 M (1000) 的左邊,來表示 400 和 900。

給定一個羅馬數字,將其轉換成整數。輸入確保在 1 到 3999 的範圍內。

示例 1:

輸入: "III"
輸出: 3

示例 2:

輸入: "IV"
輸出: 4

示例 3:

輸入: "IX"
輸出: 9

示例 4:

輸入: "LVIII"
輸出: 58
解釋: L = 50, V= 5, III = 3.

示例 5:

輸入: "MCMXCIV"
輸出: 1994
解釋: M = 1000, CM = 900, XC = 90, IV = 4.

筆者的方法:

時間200ms左右,

思路是

  • 把所有的情況放到哈希表中
  • 每次取一個位
  • 把 i 和 i+1 放一起,試試有沒有區配的,有的話把 i 和 i+1 放一起
  • 沒有的話,就是 只是計 i
    public class Solution
    {
        public int RomanToInt(string s)
        {
            char[] c = s.ToCharArray();         //將其轉為字符數組
            int sum = 0;                        //
            Hashtable hashtable = new Hashtable();
            //7個基本單位
            hashtable.Add("I", 1);
            hashtable.Add("V", 5);
            hashtable.Add("X", 10);
            hashtable.Add("L", 50);
            hashtable.Add("C", 100);
            hashtable.Add("D", 500);
            hashtable.Add("M", 1000);
            //加上6種情況
            hashtable.Add("IV", 4);
            hashtable.Add("IX", 9);
            hashtable.Add("XL", 40);
            hashtable.Add("XC", 90);
            hashtable.Add("CD", 400);
            hashtable.Add("CM", 900);

/*
* 六種情況
IV 4 IX 9
XL 40 XC 90
CD 400 CM 9000
*/

            for (int i = 0; i < c.Length; i++)
            {
                if (i + 1 < c.Length && hashtable.ContainsKey(c[i].ToString() + c[i + 1].ToString()))     //如果發現兩位一起能區配的話
                {
                    sum += int.Parse(hashtable[c[i].ToString() + c[i + 1].ToString()].ToString());        //獲取值,HashTable的類型都是Object!
                    i++;                                                                                    //跳兩位
                }
                else
                {
                    sum += int.Parse(hashtable[c[i].ToString()].ToString());
                }

            }
            return sum;
        }
    }

換成字典

    public class Solution
    {
        public int RomanToInt(string s)
        {
            char[] c = s.ToCharArray();         //將其轉為字符數組
            int sum = 0;                        //
            Dictionary<string, int> dictionary = new Dictionary<string, int>();
            //7個基本單位
            dictionary.Add("I", 1);
            dictionary.Add("V", 5);
            dictionary.Add("X", 10);
            dictionary.Add("L", 50);
            dictionary.Add("C", 100);
            dictionary.Add("D", 500);
            dictionary.Add("M", 1000);
            //加上6種情況
            dictionary.Add("IV", 4);
            dictionary.Add("IX", 9);
            dictionary.Add("XL", 40);
            dictionary.Add("XC", 90);
            dictionary.Add("CD", 400);
            dictionary.Add("CM", 900);

/*
* 六種情況
IV 4 IX 9
XL 40 XC 90
CD 400 CM 9000
*/

            for (int i = 0; i < c.Length; i++)
            {
                if (i + 1 < c.Length && dictionary.ContainsKey(c[i].ToString() + c[i + 1]))     //如果發現兩位一起能區配的話
                {
                    sum += dictionary[c[i].ToString() + c[i + 1].ToString()];        //獲取值,HashTable的類型都是Object!
                    i++;                                                                                    //跳兩位
                }
                else
                {
                    sum += dictionary[c[i].ToString()];
                }

            }
            return sum;
        }
    }

以上兩個例子都會進行較多的裝箱拆箱,下面主要使用if-else,switch,空間花銷較大,但是如果測試例子較多,進行大量計算,時間會相對少一點。

    public class Solution
    {
        public int RomanToInt(string s)
        {
            int sum = 0;                        //

            for (int i = 0; i < s.Length; i++)
            {
                if (i + 1 < s.Length)       //如果後面還有別的字符
                {
                    if (s[i] == I)
                    {
                        int a = 0;
                        switch (s[i + 1])     //"i%"
                        {
                            case V: a = 4; i++; break;
                            case X: a = 9; i++; break;
                            default: a = 1; break;
                        }
                        sum += a;
                    }
                    else if (s[i] == X)
                    {
                        int a = 0;

                        switch (s[i + 1])     //"X%"
                        {
                            case L: a = 40; i++; break;
                            case C: a = 90; i++; break;
                            default: a = 10; break;
                        }
                        sum += a;
                    }
                    else if (s[i] == C)
                    {
                        int a = 0;
                        switch (s[i + 1])     //"X%"
                        {
                            case D: a = 400; i++; break;
                            case M: a = 900; i++; break;
                            default: a = 100; break;
                        }
                        sum += a;
                    }
                    else
                    {
                        int a = 0;
                        switch (s[i])
                        {case V: a = 5; break;case L: a = 50; break;case D: a = 500; break;
                            case M: a = 1000; break;
                        }
                        sum += a;
                    }
                }

                else
                {
                    int a = 0;
                    switch (s[i])
                    {
                        case I: a = 1; break;
                        case V: a = 5; break;
                        case X: a = 10; break;
                        case L: a = 50; break;
                        case C: a = 100; break;
                        case D: a = 500; break;
                        case M: a = 1000; break;
                    }
                    sum += a;
                }
            }

            return sum;
        }
    }

C# 算法題系列(二) 各位相加、整數反轉、回文數、羅馬數字轉整數