O(nlogn) Algorithm - Find three evenly spaced ones within binary string

前端 未结 30 2958
刺人心
刺人心 2020-11-28 00:07

I had this question on an Algorithms test yesterday, and I can\'t figure out the answer. It is driving me absolutely crazy, because it was worth about 40 points. I figure

30条回答
  •  一向
    一向 (楼主)
    2020-11-28 00:39

    How about a simple O(n) solution, with O(n^2) space? (Uses the assumption that all bitwise operators work in O(1).)

    The algorithm basically works in four stages:

    Stage 1: For each bit in your original number, find out how far away the ones are, but consider only one direction. (I considered all the bits in the direction of the least significant bit.)

    Stage 2: Reverse the order of the bits in the input;

    Stage 3: Re-run step 1 on the reversed input.

    Stage 4: Compare the results from Stage 1 and Stage 3. If any bits are equally spaced above AND below we must have a hit.

    Keep in mind that no step in the above algorithm takes longer than O(n). ^_^

    As an added benefit, this algorithm will find ALL equally spaced ones from EVERY number. So for example if you get a result of "0x0005" then there are equally spaced ones at BOTH 1 and 3 units away

    I didn't really try optimizing the code below, but it is compilable C# code that seems to work.

    using System;
    
    namespace ThreeNumbers
    {
        class Program
        {
            const int uint32Length = 32;
    
            static void Main(string[] args)
            {
                Console.Write("Please enter your integer: ");
                uint input = UInt32.Parse(Console.ReadLine());
    
                uint[] distancesLower = Distances(input);
                uint[] distancesHigher = Distances(Reverse(input));
    
                PrintHits(input, distancesLower, distancesHigher);
            }
    
            /// 
            /// Returns an array showing how far the ones away from each bit in the input.  Only 
            /// considers ones at lower signifcant bits.  Index 0 represents the least significant bit 
            /// in the input.  Index 1 represents the second least significant bit in the input and so 
            /// on.  If a one is 3 away from the bit in question, then the third least significant bit 
            /// of the value will be sit.
            /// 
            /// As programed this algorithm needs: O(n) time, and O(n*log(n)) space.  
            /// (Where n is the number of bits in the input.)
            /// 
            public static uint[] Distances(uint input)
            {
                uint[] distanceToOnes = new uint[uint32Length];
                uint result = 0;
    
                //Sets how far each bit is from other ones. Going in the direction of LSB to MSB
                for (uint bitIndex = 1, arrayIndex = 0; bitIndex != 0; bitIndex <<= 1, ++arrayIndex)
                {
                    distanceToOnes[arrayIndex] = result;
                    result <<= 1;
    
                    if ((input & bitIndex) != 0)
                    {
                        result |= 1;
                    }
                }
    
                return distanceToOnes;
            }
    
            /// 
            /// Reverses the bits in the input.
            /// 
            /// As programmed this algorithm needs O(n) time and O(n) space.  
            /// (Where n is the number of bits in the input.)
            /// 
            /// 
            /// 
            public static uint Reverse(uint input)
            {
                uint reversedInput = 0;
                for (uint bitIndex = 1; bitIndex != 0; bitIndex <<= 1)
                {
                    reversedInput <<= 1;
                    reversedInput |= (uint)((input & bitIndex) != 0 ? 1 : 0);
                }
    
                return reversedInput;
            }
    
            /// 
            /// Goes through each bit in the input, to check if there are any bits equally far away in 
            /// the distancesLower and distancesHigher
            /// 
            public static void PrintHits(uint input, uint[] distancesLower, uint[] distancesHigher)
            {
                const int offset = uint32Length - 1;
    
                for (uint bitIndex = 1, arrayIndex = 0; bitIndex != 0; bitIndex <<= 1, ++arrayIndex)
                {
                    //hits checks if any bits are equally spaced away from our current value
                    bool isBitSet = (input & bitIndex) != 0;
                    uint hits = distancesLower[arrayIndex] & distancesHigher[offset - arrayIndex];
    
                    if (isBitSet && (hits != 0))
                    {
                        Console.WriteLine(String.Format("The {0}-th LSB has hits 0x{1:x4} away", arrayIndex + 1, hits));
                    }
                }
            }
        }
    }
    

    Someone will probably comment that for any sufficiently large number, bitwise operations cannot be done in O(1). You'd be right. However, I'd conjecture that every solution that uses addition, subtraction, multiplication, or division (which cannot be done by shifting) would also have that problem.

提交回复
热议问题