zoukankan      html  css  js  c++  java
  • C# 算法题系列(二) 各位相加、整数反转、回文数、罗马数字转整数

    各位相加

    给定一个非负整数 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;
            }
        }

    罗马数字转整数

    罗马数字包含以下七种字符: I, V, X, LCD 和 M

    题目地址 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;
            }
        }
  • 相关阅读:
    学习再学习···
    Verilog中文件输入与输出任务实例解析(转载)
    入门实验——流水灯
    论文的参考文献
    Testbench新接触(学习笔记)
    Verilog再接触 问题集
    verilog 语句不可综合和可综合汇总
    关于modelsim 6.4a遇到的问题
    DevExpress.XtraEditors.GridLookUpEdit 隐藏列
    Sql 计算一个词出现的次数
  • 原文地址:https://www.cnblogs.com/whuanle/p/10352752.html
Copyright © 2011-2022 走看看