算法试题:从一串数字中构造出能被15整除的最大整数

上周末布置的算法试题:

给定一行只包含数字的字符串(1到1000个数字),求使用字符串中的某些字符,构造一个能被15整除的最大整数,要求字符串中的每个字符最多只能使用一次。

该试题需要考虑什么数能被3整除和被5整除,涉及排序,当不能被3整除时需要考虑如何舍去某些数字。

 

我今天用C++编程实现了,估计应该能对。

 

一、首先编写测试用例,每对值中给出待测试的数字串和预期的结果:

 

bool AssertPair(const char* instr, const char* check);

bool Test()
{
    return AssertPair("0", "")
        && AssertPair("5", "")
        && AssertPair("1", "")
        && AssertPair("12", "")
        && AssertPair("50", "")
        && AssertPair("125", "15")
        && AssertPair("120", "210")
        && AssertPair("102", "210")
        && AssertPair("012", "210")
        && AssertPair("102", "210")
        && AssertPair("051", "510")
        && AssertPair("12310", "3210")
        && AssertPair("12320", "3210")
        && AssertPair("0223", "30")
        && AssertPair("123110", "31110")
        && AssertPair("123220", "32220");
}

 

二、编码实现代码:

 

#include <iostream>
#include <string>
using namespace std;

// 按从大到小顺序插入排序
void Sort(char* buf)
{
    for (int i = 0; buf[i]; i++)            // 对每一个输入的数字
    {
        for (int j = 0; j < i; j++)         // 按从大到小顺序插入
        {
            if (buf[i] > buf[j])            // 将 buf[i] 插入到 j 位置
            {
                char c = buf[i];
                for (int k = i; k > j; k--)
                {
                    buf[k] = buf[k - 1];
                }
                buf[j] = c;
                break;
            }
        }
    }
}

// 找到5,放到末尾
bool Move5ToEnd(string& str)
{
    size_t pos = str.find('5');

    if (pos == string::npos)
    {
        return false;
    }
    str += str[pos];
    str.erase(pos, 1);

    return true;
}

// 从倒数第二个开始往前找一个数字移除,该数字除以3的余数为指定数
bool RemoveOneChar(string& str, int rem)
{
    for (int i = (int)str.size() - 2; i >= 0; i--)
    {
        if ((str[i] - '0') % 3 == rem)
        {
            str.erase(i, 1);
            return str != "0";
        }
    }

    return false;
}

// 从倒数第二个开始往前找两个数字移除,该数字之和除以3的余数为指定数
bool RemoveTwoChars(string& str, int rem)
{
    for (int i = (int)str.size() - 2; i >= 0; i--)
    {
        for (int j = i - 1; j >= 0; j--)
        {
            if ((str[i] - '0' + str[j] - '0') % 3 == rem)
            {
                str.erase(i, 1);
                str.erase(j, 1);
                return str != "0";
            }
        }
    }

    return false;
}

// 将一行中各个数字组成能被15整除的最大整数
bool GetMaxInt(string& str)
{
    // 去掉不是数字的字符
    for (int t = (int)str.size() - 1; t >= 0; t--)
    {
        if (!isdigit(str[t]))
        {
            str.erase(t, 1);
        }
    }

    // 从大到小排序
    Sort(&str[0]);

    // 如果末位不是0,则找到5,放到末尾,这样就能被5整除
    if (*str.rbegin() != '0' && !Move5ToEnd(str))
    {
        return false;
    }

    // 求所有数字之和
    int sum = 0;
    for (size_t i = 0; i < str.size(); i++)
    {
        sum += str[i] - '0';
    }

    // 根据除以3的余数,从倒数第二个开始往前找数字移除
    return sum > 0 &&                       // 0不能被整除
        (sum % 3 == 0                       // 正好被3整除
        || RemoveOneChar(str, sum % 3)      // 移除一个数字,该数字除3余指定数
        || RemoveTwoChars(str, sum % 3));   // 移除两个数字,其和除3余指定数
}

int main()
{
    printf(Test() ? "Test OK.\n" : "Test fail.\n");
    string str;

    cout << "请输入多行数字,将输出每行中各数字组成的能被15整除的最大整数。\n";

    for (;;)
    {
        cin >> str;
        if (str.empty() || str[0] == 'q')
        {
            break;
        }

        if (GetMaxInt(str))
        {
            printf("%s\n\n", str.c_str());
        }
        else
        {
            printf("Imporssible.\n\n");
        }
    }

    return 0;
}

bool AssertPair(const char* instr, const char* check)
{
    string str(instr);
    bool ret = GetMaxInt(str)
        ? strcmp(check, str.c_str()) == 0
        : strcmp(check, "") == 0;

    printf("%s\tinput: %s\toutput: %s\tcheck: %s\n",
        ret ? "OK." : "Fail.",
        instr, str.c_str(),
        *check ? check : "Imporssible");

    return ret;
}

posted @ 2011-03-12 22:31  张云贵  Views(1874)  Comments(0Edit  收藏  举报