程序以查找字符串中的最小数字

时间:2015-04-08 15:12:31

标签: c# algorithm

我有一个像这样的c#类

internal class QueuedMinimumNumberFinder : ConcurrentQueue<int>
{
    private readonly string _minString;
    public QueuedMinimumNumberFinder(string number, int takeOutAmount)
    {
        if (number.Length < takeOutAmount)
        {
            throw new Exception("Error *");
        }
        var queueIndex = 0;
        var queueAmount = number.Length - takeOutAmount;
        var numQueue = new ConcurrentQueue<int>(number.ToCharArray().Where(m => (int) Char.GetNumericValue(m) != 0).Select(m=>(int)Char.GetNumericValue(m)).OrderBy(m=>m));
        var zeroes = number.Length - numQueue.Count;
        while (queueIndex < queueAmount)
        {
            int next;
            if (queueIndex == 0)
            {
                numQueue.TryDequeue(out next);
                Enqueue(next);
            } else
            {
                if (zeroes > 0)
                {
                    Enqueue(0);
                    zeroes--;
                } else
                {
                    numQueue.TryDequeue(out next);
                    Enqueue(next);
                }
            }
            queueIndex++;
        }
        var builder = new StringBuilder();
        while (Count > 0)
        {
            int next = 0;
            TryDequeue(out next);
            builder.Append(next.ToString());
        }
        _minString = builder.ToString();
    }

    public override string ToString() { return _minString; }
}

程序的目的是找到可以通过从字符串中取出任意x个字符来实现的最小可能整数(例如,100023是字符串,如果你取出任何3个字母,则创建的最小int将是100)。我的问题是,这是正确的方法吗?是否有更好的数据结构可用于此问题?

首先编辑:

以下是它现在的样子

 internal class QueuedMinimumNumberFinder
    {
        private readonly string _minString;
        public QueuedMinimumNumberFinder(string number, int takeOutAmount)
        {
            var queue = new Queue<int>();
            if (number.Length < takeOutAmount)
            {
                throw new Exception("Error *");
            }
            var queueIndex = 0;
            var queueAmount = number.Length - takeOutAmount;
            var numQueue = new List<int>(number.Where(m=>(int)Char.GetNumericValue(m)!=0).Select(m=>(int)Char.GetNumericValue(m))).ToList();
            var zeroes = number.Length - numQueue.Count;
            while (queueIndex < queueAmount)
            {
                if (queueIndex == 0)
                {
                    var nextMin = numQueue.Min();
                    numQueue.Remove(nextMin);
                    queue.Enqueue(nextMin);
                } else
                {
                    if (zeroes > 1)
                    {
                        queue.Enqueue(0);
                        zeroes--;
                    } else
                    {
                        var nextMin = numQueue.Min();
                        numQueue.Remove(nextMin);
                        queue.Enqueue(nextMin);
                    }
                }
                queueIndex++;
            }
            var builder = new StringBuilder();
            while (queue.Count > 0)
            {
                builder.Append(queue.Dequeue().ToString());
            }
            _minString = builder.ToString();
        }

        public override string ToString() { return _minString; }
    }

6 个答案:

答案 0 :(得分:1)

这是我使用LINQ的解决方案:

public string MinimumNumberFinder(string number, int takeOutAmount)
{
    var ordered = number.OrderBy(n => n);
    var nonZero = ordered.SkipWhile(n => n == '0');
    var zero = ordered.TakeWhile(n => n == '0');

    var result = nonZero.Take(1)
                        .Concat(zero)
                        .Concat(nonZero.Skip(1))
                        .Take(number.Length - takeOutAmount);   

    return new string(result.ToArray());
}

答案 1 :(得分:1)

只需计算每个数字出现的次数。一个10号的数组就可以了。 Count [i]给出数字i的计数。

然后先选择最小的非零i,然后选择最小的等号并形成你的号码。

答案 2 :(得分:1)

一旦您意识到输入字符串数字仅映射到10个可能值的域中,就可以实现非常简单有效的实现:&#39; 0&#39; ..&#39; 9&#39;。

这可以使用10个整数的简单数组编码为输入字符串中特定数字的出现次数:var digit_count = new int[10];

@MasterGillBates在他的answer

中描述了这个想法

然后,您可以将此数组视为您的优先级队列,您可以通过迭代删除最低可用字符(减少其在数组中的出现次数)来使您需要的字符出列。

下面的代码示例提供了此想法的示例实现。

public static class MinNumberSolver
{
    public static string GetMinString(string number, int takeOutAmount)
    {
        // "Add" the string by simply counting digit occurrance frequency.
        var digit_count = new int[10];
        foreach (var c in number)
            if (char.IsDigit(c))
                digit_count[c - '0']++;

        // Now remove them one by one in lowest to highest order.

        // For the first character we skip any potential leading 0s
        var selected = new char[takeOutAmount];
        var start_index = 1;
        selected[0] = TakeLowest(digit_count, ref start_index);

        // For the rest we start in digit order at '0' first.
        start_index = 0;
        for (var i = 0; i < takeOutAmount - 1; i++)
            selected[1 + i] = TakeLowest(digit_count, ref start_index);

        // And return the result.
        return new string(selected);
    }

    private static char TakeLowest(int[] digit_count, ref int start_index)
    {
        for (var i = start_index; i < digit_count.Length; i++)
        {
            if (digit_count[i] > 0)
            {
                start_index = ((--digit_count[i] > 0) ? i : i + 1);
                return (char)('0' + i);
            }
        }
        throw new InvalidDataException("Input string does not have sufficient digits");
    }
}

答案 3 :(得分:0)

您可以将每个整数放入一个列表中,并查找这些值中所有可能的sequences。从序列列表中,您可以通过仅采用具有所需整数数的集合进行排序。从那里,您可以编写一个快速函数,将序列解析为整数。接下来,您可以将所有已解析的序列存储到数组或其他数据结构中,并根据值进行排序,这样您就可以从数据结构中选择最小数量。可能有更简单的方法可以做到这一点,但这肯定会起作用,并为您提供数字所需数字的选项。

答案 4 :(得分:0)

如果我正确理解了这一点,为什么不从大于零的最小数字开始挑选数字。然后挑出所有零,然后挑选任何剩余数字,如果所有零被拾取。这完全取决于结束结果的长度

在您的示例中,您有一个6位数字,并且您想要挑选3位数字。这意味着您只剩下3位数字。如果它是一个10位数字,那么你最终会得到一个7位数字等等......

因此,有一个算法可以知道您的起始号码的长度,您计划删除的位数,以及结束号码的长度。然后挑出数字。

这只是快速而又脏的代码:

string startingNumber = "9999903040404"; // "100023";
int numberOfCharactersToRemove = 3;

string endingNumber = string.Empty;
int endingNumberLength = startingNumber.Length - numberOfCharactersToRemove;

while (endingNumber.Length < endingNumberLength)
{
    if (string.IsNullOrEmpty(endingNumber))
    {
        // Find the smallest digit in the starting number
        for (int i = 1; i <= 9; i++)
        {
            if (startingNumber.Contains(i.ToString()))
            {
                endingNumber += i.ToString();
                startingNumber = startingNumber.Remove(startingNumber.IndexOf(i.ToString()), 1);
                break;
            }
        }
    }
    else if (startingNumber.Contains("0"))
    {
        // Add any zeroes
        endingNumber += "0";
        startingNumber = startingNumber.Remove(startingNumber.IndexOf("0"), 1);
    }
    else
    {
        // Add any remaining numbers from least to greatest
        for (int i = 1; i <= 9; i++)
        {
            if (startingNumber.Contains(i.ToString()))
            {
                endingNumber += i.ToString();
                startingNumber = startingNumber.Remove(startingNumber.IndexOf(i.ToString()), 1);
                break;
            }
        }
    }
}

Console.WriteLine(endingNumber);

100023起始编号导致100为最终结果

9999903040404起始编号导致3000044499为最终结果

答案 5 :(得分:0)

这是解决此问题的我的版本:


设计

  • 您可以使用binary tree对列表进行排序,其中有很多 实现,我选择了这个one
  • 然后你可以跟踪你所拥有的零的数量 string最后你会得到两个列表:我命名为一个 SortedDigitsList ,另一个 ZeroDigitsList
  • 执行切换案例以确定最后3位应该是什么 返回

这里是完整的代码:

 class MainProgram2
{
    static void Main()
    {
        Tree theTree = new Tree();
        Console.WriteLine("Please Enter the string you want to process:"); 
        string input = Console.ReadLine();
        foreach (char c in input)
        {
            // Check if it's a digit or not
            if (c >= '0' && c <= '9')
            {
                theTree.Insert((int)Char.GetNumericValue(c));
            }

        }
        //End of for each (char c in input)


        Console.WriteLine("Inorder traversal resulting Tree Sort without the zeros");
        theTree.Inorder(theTree.ReturnRoot());
        Console.WriteLine(" ");

        //Format the output depending on how many zeros you have
        Console.WriteLine("The final 3 digits are");
        switch (theTree.ZeroDigitsList.Count)
        {
            case 0:
                {
                    Console.WriteLine("{0}{1}{2}", theTree.SortedDigitsList[0], theTree.SortedDigitsList[1], theTree.SortedDigitsList[2]);
                    break;
                }
            case 1:
                {
                    Console.WriteLine("{0}{1}{2}", theTree.SortedDigitsList[0], 0, theTree.SortedDigitsList[2]);
                    break;
                }
            default:
                {
                    Console.WriteLine("{0}{1}{2}", theTree.SortedDigitsList[0], 0, 0);
                    break;
                }

        }


        Console.ReadLine();
    }

}//End of main()
 }

class Node
{
    public int item;
    public Node leftChild;
    public Node rightChild;
    public void displayNode()
    {
        Console.Write("[");
        Console.Write(item);
        Console.Write("]");
    }
}
class Tree 
{

public List<int> SortedDigitsList { get; set; }
public List<int> ZeroDigitsList { get; set; }
public Node root;
public Tree()
{

    root = null;
    SortedDigitsList = new List<int>();
    ZeroDigitsList = new List<int>();


}
public Node ReturnRoot()
{
    return root;
}
public void Insert(int id)
{
    Node newNode = new Node();
    newNode.item = id;
    if (root == null)
        root = newNode;
    else
    {
        Node current = root;
        Node parent;
        while (true)
        {
            parent = current;
            if (id < current.item)
            {
                current = current.leftChild;
                if (current == null)
                {
                    parent.leftChild = newNode;
                    return;
                }
            }
            else
            {
                current = current.rightChild;
                if (current == null)
                {
                    parent.rightChild = newNode;
                    return;
                }
            }
        }
    }
}
//public void Preorder(Node Root)
//{
//    if (Root != null)
//    {
//        Console.Write(Root.item + " ");
//        Preorder(Root.leftChild);
//        Preorder(Root.rightChild);
//    }
//}

public void Inorder(Node Root)
{
    if (Root != null)
    {
        Inorder(Root.leftChild);
        if (Root.item > 0)
        {
            SortedDigitsList.Add(Root.item);
            Console.Write(Root.item + " ");
        }
        else
        {
            ZeroDigitsList.Add(Root.item);
        }
        Inorder(Root.rightChild);
    }

}