1

I have the following code but it takes 20sec to process the 52957 inputs of type BigInteger. This is the question that i want to solve https://www.hackerearth.com/problem/algorithm/girlfriends-demands/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Numerics;
namespace girldfriends_demands
{
    class Program
    {
        private static string inputString = String.Empty;
        private static int testCases=0;
        private static BigInteger[,] indexArray;
        static void Main(string[] args)
        {
            initialize();
            printDemand();
            Console.ReadLine();
        }
        private static void initialize()
        {
            inputString = Console.ReadLine();
            testCases = int.Parse(Console.ReadLine());
            indexArray = new BigInteger[testCases, 2];
            for (int i = 0; i < testCases; i++)
            {
                string[] tokens = Console.ReadLine().Split();
                indexArray[i, 0] = BigInteger.Parse(tokens[0]);
                indexArray[i, 1] = BigInteger.Parse(tokens[1]);
            }
        }

        private static void printDemand()
        {
            char[] convertedString = inputString.ToCharArray();
            for (int i = 0; i < testCases; i++)
            {

                BigInteger length=inputString.Length;
                BigInteger startf, endf; ; 
                BigInteger.DivRem(indexArray[i, 0] - 1,length,out startf);
                BigInteger.DivRem(indexArray[i, 1]-1,length,out endf);
                char c=convertedString[((int)startf)];
                char e=convertedString[((int)endf)];
                if(c==e)
                {
                    Console.WriteLine("Yes");
                }
                else
                {
                    Console.WriteLine("No");
                }
            }
        }
    }
}

Please specify how to reduce the time complexity of the code.This program gets the letters at the specified position in a string and prints true if they are same else false. Also computing the range at prior to the loop isn't helping

  • And do you have also example input set ? Console.WriteLine is a big slowdown - writing to memory/dumping output at the end of loop is faster. – Ondrej Svejdar Sep 02 '15 at 08:42
  • @OndrejSvejdar Here is the sample input – Aarthna Maheshwari Sep 02 '15 at 08:48
  • 20 seconds? That's absurd. What are you trying to do anyway? Why not simply compare the two strings directly, instead of converting them to `BigInteger` and then doing complicated math stuff? There's about a million unnecessary things you're doing (why convert `inputString` to `char[]`? Why load all the data into memory at once instead of processing line by line? Why keep things so painfully procedural? Are you coming from a Pascal background? – Luaan Sep 02 '15 at 09:01
  • what is DivRem.is it divide and conquer algorithm? – Arash Sep 02 '15 at 09:15
  • @Luaan have to compare a particular character of a string and that character is specified by the index in the input – Aarthna Maheshwari Sep 02 '15 at 09:17
  • @Arashjo it will divide the given biginters and will return the remainder in the given variable – Aarthna Maheshwari Sep 02 '15 at 09:17
  • @AarthnaMaheshwari Thanks for the link. Just to clarify, the `DivRem` method is used to handle overflow. If my string is 10 characters in length, and it's looking for an index of 15, that code uses the remainder (5) to choose the 'real' index. So it doesn't really matter if a BigInteger exceeds the length of a string. Is that correct? – Michael McMullin Sep 02 '15 at 09:47
  • @MichaelMcMullin Divrem Divides one BigInteger value by another, returns the result, and returns the remainder in an output parameter. – Aarthna Maheshwari Sep 02 '15 at 11:51

4 Answers4

4

Why you use BigInteger ? In any case string.length is typeof int. It mean that if your string exceed 2147483647 (2^31 -1) your program will be broken.

I think changing BigInteger to int will help.

bot_insane
  • 2,545
  • 18
  • 40
3
Console.ReadLine().Split()

is the biggest of your problems. For every single line in the file, you create an array of strings, one letter per string. This is a huge performance drain, and almost certainly not what you intended - in particular, it would be wholy unnecessary to use BigInteger to store a single-digit number...

I assume that you actually want to split the line in two based on some delimiter. For example, if your numbers are separated by a comma, you can use

Console.ReadLine().Split(',')

Even then, there is little reason to use BigInteger at all. The operation you're trying to perform is distinctly string-based, and very easy to do with strings. However, I can't really help you more specifically, because your problem description is incredibly ambiguous for such a simple task, and the code is so obviously wrong it's entirely useless to guess at what exactly you're trying to do.

EDIT:

Okay, your link confirmed my assumptions - you are massively overcomplicating this. For example, code like this will do:

var word = Console.ReadLine();
var items = int.Parse(Console.ReadLine());

for (var _ = 0; _ < items; _++)
{
    var indices = 
          Console.ReadLine()
           .Split(' ')
           .Select(i => (int)((long.Parse(i) - 1) % word.Length))
               .ToArray();

    Console.WriteLine(word[indices[0]] == word[indices[1]] ? "Yes" : "No");
}

First, note that the numbers will always fit in a long, which allows you to avoid using BigIntever. Second, you need to use Split properly - in this case, the delimiter is a space. Third, there's no reason not to do the whole processing in a single stream - waiting for the whole input, collecting it in memory and then outputting everything at once is a waste of memory. Fourth, note how easy it was to avoid most of the complex checks while incorporating the whole necessary mechanism in simple arithmetic operations.

This runs under 2 seconds on each of the input data, only using ~80kiB of memory.

I think that ideologically, this fits the site perfectly - it's very simple and straightforward and works for all the expected inputs - the perfect hack. Of course, you'd want extra checks if this was for an end-user application, but the HackerEarth site name implies hacks are what's expected, really.

Luaan
  • 62,244
  • 7
  • 97
  • 116
  • the numbers are seperated by space and i have to use biginteger coz the inputs are like this 720031795465148928 347859163354280992 – Aarthna Maheshwari Sep 02 '15 at 09:15
  • I'm not sure if this is the bottleneck -- I presume `printDemand()` is the method that's taking 20 seconds to execute. Any inefficiencies in the `initialize()` method will likely go unnoticed, as it's awaiting user input. – Michael McMullin Sep 02 '15 at 09:18
  • @MichaelMcMullin i too feel the same – Aarthna Maheshwari Sep 02 '15 at 09:31
  • @MichaelMcMullin Do you really think somebody is inputting `720031795465148928 347859163354280992` manually using the console? It seems to me that it's obviously expecting the data to be piped in. – Luaan Sep 02 '15 at 11:44
  • @AarthnaMaheswari Check my submission to see what I think the author intended. In any case, I still think that your biggest problem is the `Split` - have you tried fixing that? – Luaan Sep 02 '15 at 12:06
1

In my experience, frequent Console.WriteLine calls can lead to huge execution times.

Instead of calling that function whenever you want to add some output, I think you should use a StringBuilder object, and append all your output to it. Then, after the for-loop, call Console.WriteLine once to print the StringBuilder's contents.

This might not be your program's biggest problem, but it will help quite a bit.

Lee White
  • 3,649
  • 8
  • 37
  • 62
0

Myabe by removing casts in these line and using string.compare you cand decrease execution time

            if(string.Compare(startf.ToString(), endf.ToString()))
            {
                Console.WriteLine("Yes");
                continue;
             }
                Console.WriteLine("No");
Arash
  • 889
  • 7
  • 18