算法实战:给定一个带通配符问号的数W,问号可以代表任意一个一位数字。 再给定一个整数X,和W具有同样的长度。 问有多少个整数符合W的形式并且比X大?

如题:

给定一个带通配符问号的数W,问号可以代表任意一个一位数字。

再给定一个整数X,和W具有同样的长度。
问有多少个整数符合W的形式并且比X大?

输入格式
多组数据,每组数据两行,第一行是W,第二行是X,它们长度相同。在[1..10]之间.
输出格式
每行一个整数表示结果。

答题说明
输入样例
36?1?8
236428
8?3
910
?
5
输出样例
100
0
4

分析如下:
先用穷举法来分析几种可能情况
1.
36?1?8
236428
如果W第一个通配符之前的数字大于X,则通通配符可以是任意数字,因此W比X大的个数就是10的n次方(通配符个数n)
2.
8?3
910
如果W第一个通配符之前的数字小于x,则W不可能比X大,结果为0
3.
2?
25
如果W第一个通配符之前的数字等于x,这时,只有W的通配符比X相应位置的数字大的情况,才有可能使w比X大,因此通配符前面的数字不起任何作用,
我们可以把它简化为

5
此时可以得到结果为4

分析完了第一个通配符我们来分析第二个通配符,这时我们发现,只有第一个通配符前面没有数字或数字和x相等的情况下,我们才需要考虑第二个通配符。

并且情况很相似,只有第一个通配符和x相同位置中的数字相等的情况,我们才需要对第二个通配符进行分析,
否则,跟上面的情况类似,
如果第一个通配符大于x中的数字,则W比X大的个数就是10的n-1次方(通配符个数n)
如果第一个通配符小于x中的数字,则W比X大的个数就是0

以此类推,就可以得出W比X大总个数

c#示例代码如下:


        /// <summary>
        /// 使用算法推算w大于x的个数
        /// </summary>
        /// <param name="string_W"></param>
        /// <param name="string_X"></param>
        /// <returns></returns>
        private int getNum(string string_W, string string_X)
        {
            if (int.Parse(string_W.Replace('?', '9')) <= int.Parse(string_X))
            {
                return 0;
            }

            int firstCharIndex = -1;//第一个通配符的索引
            int secondCharIndex = -1;//第二个通配符的索引
            int value_x = 0;字符串string_X中在第一个通配符相应位置的数字的值
            int charCount = 0;//通配符数量

            //找到第一个通配符的索引和第二个通配符的索引
            for (int i = 0; i < string_W.Length; i++)
            {
                if (string_W[i] == '?')
                {
                    charCount++;

                    if (firstCharIndex == -1)
                    {
                        value_x = int.Parse(string_X[i].ToString());
                        firstCharIndex = i;
                        continue;
                    }
                    if (firstCharIndex != -1 && secondCharIndex == -1)
                    {
                        secondCharIndex = i;
                    }
                }
            }
            //第一个通配符前面有数字,并且与x不相等的情况
            if (firstCharIndex > 0)
            {
                int formerValue_W = int.Parse(string_W.Substring(0, firstCharIndex));
                int formerValue_X = int.Parse(string_X.Substring(0, firstCharIndex));
                if (formerValue_W > formerValue_X)
                {
                    //如果之前的数据W>X,则=通配符的个数n  10的n次方
                    return (int)Math.Pow(10, charCount);
                }
                else if (formerValue_W < formerValue_X)
                {
                    return 0;
                }
            }

            //如果第一个通配符之前的数相等或没有数字,判断通配符和X字符的大小情况
            if (charCount > 1)
            {
                //递归计算出结果  第一个通配符大于x的情况+等于x时进行递归推算
                return (9 - value_x) * (int)Math.Pow(10, charCount - 1) +
                    getNum(string_W.Substring(firstCharIndex + 1), string_X.Substring(firstCharIndex + 1));
            }
            else
            {
                //只有一个通配符,判断当通配符与x相同位置的整数相同时,w和x的大小
                int W = int.Parse(string_W.Replace('?', string_X[firstCharIndex]));
                int X = int.Parse(string_X);
                if (W > X)
                {
                    return (9 - value_x) + 1;
                }
                else
                {
                    return (9 - value_x);
                }
            }
        }
        /// <summary>
        /// 使用常规逻辑遍历计算w大于x的个数
        /// </summary>
        /// <param name="string_W"></param>
        /// <param name="string_X"></param>
        /// <returns></returns>
        private int CalNum(string string_W, string string_X)
        {
            int value_x = int.Parse(string_X);

            string[] parms_w = string_W.Split('?');

            string[] charDic = new string[] { "a", "b", "c", "d", "e", "f", "g", "h", "l", "m" };//最多10个
            //字符字典,用于依次替换string_W中的通配符,以方便递归方法中的遍历
            string_W = "";

            for (int i = 0; i < parms_w.Length; i++)
            {
                string_W += parms_w[i] + charDic[i];
            }
            string_W = string_W.Substring (0,string_W .Length -1);
            int charCount = parms_w.Length - 1;

            return CalNum_sub(string_W, value_x, charDic, charCount); ;
        }
        /// <summary>
        /// CalNum方法中用到的递归计算
        /// </summary>
        /// <param name="string_W"></param>
        /// <param name="value_x"></param>
        /// <param name="charDic"></param>
        /// <param name="charCount"></param>
        /// <returns></returns>
        private int CalNum_sub(string string_W, int value_x, string[] charDic, int charCount)
        {
            int total = 0;

            for (int k = 0; k < 10; k++)
            {
                string temp = string_W.Replace(charDic[charCount - 1], k.ToString());
                if (charCount > 1)
                {
                    total += CalNum_sub(temp, value_x, charDic, charCount - 1);
                }
                else
                {
                    if (int.Parse(temp) > value_x)
                    {
                        total++;
                    }
                }
            }
            return total;
        }

        /// <summary>
        /// 测试方法
        /// </summary>
        /// <param name="string_W"></param>
        /// <param name="string_X"></param>
        /// <returns></returns>
        private string testNum(string string_W, string string_X)
        {
            Stopwatch watch = new Stopwatch();
            watch.Start();
            int v1 = CalNum(string_W, string_X);
            watch.Stop();
            string t1 = watch.ElapsedTicks.ToString();
            watch.Reset();
            watch.Start();
            int v2 = getNum(string_W, string_X);
            watch.Stop();
            string t2 = watch.ElapsedTicks.ToString();
            return (v1 + "--" + v2 + "\r\n" + t1 + "--" + t2).ToString();
        }


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值