I've been reading this site long enough to know not to hide that this is a homework assignment. But I am trying to write a code that can generate all possible combinations of a string of only 0's and 1's. If the length of the string is n^2, then there will be n 1's and the rest will be 0's. The length is always a perfect square. I am coding in C and I have been trying to do it in nested loops but it seems like it could be done more easily in a recursive manner, I'm just not sure how to get that set up. Any tips or advice would be greatly appreciated.
pseudocode:
myfun(pos,length, ones)
if (length==0)
pos='\0'
#print, collect, whatever...
return
if (length>ones)
pos='0'
myfun(pos+1,length-1, ones)
pos='1'
myfun(pos+1, length-1, ones-1)
task(n)
#allocate n^2 buffer
myfun(buffer, n*n, n)
I'm not sure that this problem lends itself to recursion. In C (and most languages), every time you call a function you create a stack frame and use a few processor cycles and a chunk of stack memory. Any recursive solution to this problem will create n^2 stack frames, even the the recursion itself is only adding one bit of information.
A really bad solution is outlined below. What it doesn't do:
Exploit the fact that n is always a perfect square.
Use memory in a very intelligent way
Frees any of the memory it uses
Might not even work. ;)
...but it might give you an idea of the basic pattern.
void foo(int zeros_left, int length_left, char *s)
{
if (length_left == 0)
printf("%s\n", s);
else
{
if (zeros_left > 0)
{
char *next = malloc(strlen(s) + 2);
strcpy(next, s);
strcat(next, "0");
foo(zeros_left - 1, length_left - 1, next);
}
if (zeros_left != length_left)
{
char *next = malloc(strlen(s) + 2);
strcpy(next, s);
strcat(next, "1");
foo(zeros_left, length_left - 1, next);
}
}
}
The key to modelling a problem recursively is to break a larger version of the problem into a simple calculation combined with a smaller version of the same problem, and a trivial case that terminates the recursion.
In this case, the problem is:
For non-negative M and N, output all strings of length M that contain exactly N 1s.
You can break this down into:
If M = 0, then output an empty string; otherwise
Output all strings of length M-1 that contain exactly N 1s, prefixing each with an 0; and
If N > 0, then output all strings of length M-1 that contain exactly N-1 1s, prefixing each with a 1.
Here, M = 0 is the trivial case that terminates the recursion. Turning the above into code is reasonably simple.
Related
I have a quite peculiar case here. I have a file containing several million entries and want to find out if there exists at least one duplicate. The language here isn't of great importance, but C seems like a reasonable choice for speed. Now, what I want to know is what kind of approach to take to this? Speed is the primary goal here. Naturally, we want to stop looking as soon as one duplicate is found, that's clear, but when the data comes in, I don't know anything about how it's sorted. I just know it's a file of strings, separated by newline. Now keep in mind, all I want to find out is if a duplicate exists. Now, I have found a lot of SO questions regarding finding all duplicates in an array, but most of them go the easy and comprehensive way, rather than the fastest.
Hence, I'm wondering: what is the fastest way to find out if an array contains at least one duplicate? So far, the closest I've been able to find on SO is this: Finding out the duplicate element in an array. The language chosen isn't important, but since it is, after all, programming, multi-threading would be a possibility (I'm just not sure if that's a feasible way to go about it).
Finally, the strings have a format of XXXNNN (3 characters and 3 integers).
Please note that this is not strictly theoretical. It will be tested on a machine (Intel i7 with 8GB RAM), so I do have to take into consideration the time of making a string comparison etc. Which is why I'm also wondering if it could be faster to split the strings in two, and first compare the integer part, as an int comparison will be quicker, and then the string part? Of course, that will also require me to split the string and cast the second half to an int, which might be slower...
Finally, the strings have a format of XXXNNN (3 characters and 3 integers).
Knowing your key domain is essential to this sort of problem, so this allows us to massively simplify the solution (and this answer).
If X ∈ {A..Z} and N ∈ {0..9}, that gives 263 * 103 = 17,576,000 possible values ... a bitset (essentially a trivial, perfect Bloom filter with no false positives) would take ~2Mb for this.
Here you go: a python script to generate all possible 17 million keys:
import itertools
from string import ascii_uppercase
for prefix in itertools.product(ascii_uppercase, repeat=3):
for numeric in range(1000):
print "%s%03d" % (''.join(prefix), numeric)
and a simple C bitset filter:
#include <limits.h>
/* convert number of bits into number of bytes */
int filterByteSize(int max) {
return (max + CHAR_BIT - 1) / CHAR_BIT;
}
/* set bit #value in the filter, returning non-zero if it was already set */
int filterTestAndSet(unsigned char *filter, int value) {
int byteIndex = value / CHAR_BIT;
unsigned char mask = 1 << (value % CHAR_BIT);
unsigned char byte = filter[byteIndex];
filter[byteIndex] = byte | mask;
return byte & mask;
}
which for your purposes you'd use like so:
#include <stdlib.h>
/* allocate filter suitable for this question */
unsigned char *allocMyFilter() {
int maxKey = 26 * 26 * 26 * 10 * 10 * 10;
return calloc(filterByteSize(maxKey), 1);
}
/* key conversion - yes, it's horrible */
int testAndSetMyKey(unsigned char *filter, char *s) {
int alpha = s[0]-'A' + 26*(s[1]-'A' + 26*(s[2]-'A'));
int numeric = s[3]-'0' + 10*(s[4]-'0' + 10*(s[5]-'0'));
int key = numeric + 1000 * alpha;
return filterTestAndSet(filter, key);
}
#include <stdio.h>
int main() {
unsigned char *filter = allocMyFilter();
char key[8]; /* 6 chars + newline + nul */
while (fgets(key, sizeof(key), stdin)) {
if (testAndSetMyKey(filter, key)) {
printf("collision: %s\n", key);
return 1;
}
}
return 0;
}
This is linear, although there's obviously scope to optimise the key conversion and file input. Anyway, sample run:
useless:~/Source/40044744 $ python filter_test.py > filter_ok.txt
useless:~/Source/40044744 $ time ./filter < filter_ok.txt
real 0m0.474s
user 0m0.436s
sys 0m0.036s
useless:~/Source/40044744 $ cat filter_ok.txt filter_ok.txt > filter_fail.txt
useless:~/Source/40044744 $ time ./filter < filter_fail.txt
collision: AAA000
real 0m0.467s
user 0m0.452s
sys 0m0.016s
admittedly the input file is cached in memory for these runs.
The reasonable answer is to keep the algorithm with the smallest complexity. I encourage you to use a HashTable to keep track of inserted elements; the final algorithm complexity is O(n), because search in HashTable is O(1) theoretically. In your case I suggest you, to run the algorithm when reading file.
public static bool ThereAreDuplicates(string[] inputs)
{
var hashTable = new Hashtable();
foreach (var input in inputs)
{
if (hashTable[input] != null)
return true;
hashTable.Add(input, string.Empty);
}
return false;
}
A fast but inefficient memory solution would use
// Entries are AAA####
char found[(size_t)36*36*36*36*36*36 /* 2,176,782,336 */] = { 0 }; // or calloc() this
char buffer[100];
while (fgets(buffer, sizeof buffer, istream)) {
unsigned long index = strtoul(buffer, NULL, 36);
if (found[index]++) {
Dupe_found();
break;
}
}
The trouble with the post is that it wants "Fastest algorithm", but does not detail memory concerns and its relative importance to speed. So speed must be king and the above wastes little time. It does meet the "stop looking as soon as one duplicate is found" requirement.
Depending on how many different things there can be you have some options:
Sort whole array and then lookup for repeating element, complexity O(n log n) but can be done in place, so memory will be O(1)
Build set of all elements. Depending on chosen set implementation can be O(n) (when it will be hash set) or O(n log n) (binary tree), but it would cost you some memory to do so.
The fastest way to find out if an array contains at least one duplicate is to use a bitmap, multiple CPUs and an (atomic or not) "test and set bit" instruction (e.g. lock bts on 80x86).
The general idea is to divide the array into "total elements / number of CPUs" sized pieces and give each piece to a different CPU. Each CPU processes it's piece of the array by calculating an integer and doing the atomic "test and set bit" for the bit corresponding to that integer.
However, the problem with this approach is that you're modifying something that all CPUs are using (the bitmap). A better idea is to give each CPU a range of integers (e.g. CPU number N does all integers from "(min - max) * N / CPUs" to "(min - max) * (N+1) / CPUs"). This means that all CPUs read from the entire array, but each CPU only modifies it's own private piece of the bitmap. This avoids some performance problems involved with cache coherency protocols ("read for ownership of cache line") and also avoids the need for atomic instructions.
Then next step beyond that is to look at how you're converting your "3 characters and 3 digits" strings into an integer. Ideally, this can/would be done using SIMD; which would require that the array is in "structure of arrays" format (and not the more likely "array of structures" format). Also note that you can convert the strings to integers first (in an "each CPU does a subset of the strings" way) to avoid the need for each CPU to convert each string and pack more into each cache line.
Since you have several million entries I think the best algorithm would be counting sort. Counting sort does exactly what you asked: it sorts an array by counting how many times every element exists. So you could write a function that does the counting sort to the array :
void counting_sort(int a[],int n,int max)
{
int count[max+1]={0},i;
for(i=0;i<n;++i){
count[a[i]]++;
if (count[a[i]]>=2) return 1;
}
return 0;
}
Where you should first find the max element (in O(n)). The asymptotic time complexity of counting sort is O(max(n,M)) where M is the max value found in the array. So because you have several million entries if M has size order of some millions this will work in O(n) (or less for counting sort but because you need to find M it is O(n)). If also you know that there is no way that M is greater than some millions than you would be sure that this gives O(n) and not just O(max(n,M)).
You can see counting sort visualization to understand it better, here:
https://www.cs.usfca.edu/~galles/visualization/CountingSort.html
Note that in the above function we don't implement exactly counting sort, we stop when we find a duplicate which is even more efficient, since yo only want to know if there is a duplicate.
I've been looking at the following problem:
Magic Index: A magic index in an array A[0...n-1] is defined to be an index i such as A[i] = i. Given a sorted non-distinct array of integers, write a method to find a magic index if one exists.
Here is my solution:
static int magicNonDistinct(int[] array, int start, int end) {
if (end < start) return -1;
int mid = start + (end - start) / 2;
if (mid < 0 || mid >= array.length) return -1;
int v = array[mid];
if (v == mid) return mid;
int leftEnd = Math.min(v, mid - 1);
int leftRes = magicNonDistinct(array, start, leftEnd);
if (leftRes != -1) return leftRes;
int rightStart = Math.max(v, mid + 1);
int rightRes = magicNonDistinct(array, rightStart, end);
return rightRes;
}
It works just fine and is the recommended solution from the book Cracking The Code Interview 6th Edition, problem 8.3 Follow up (sorry for spoiling).
However when running this on a distinct array with no magic index, it visits all the elements, yielding a worst case running time of O(n).
Since it is recursive it takes O(n) memory as worst case.
Why would this solution be preferable to just iterating over the array? This solution (my own) is better I would argue:
static int magicNonDistinctV2(int[] array) {
for (int i = 0; i < array.length; ++i) {
int v = array[i];
if (v == i) return v;
if (v >= array.length) return -1;
else if (v > i) i = v - 1;
}
return -1;
}
O(n) running time O(1) space always?
Could somebody derive a better time complexity for the initial algorithm? I've been thinking about looking if it is O(d), where d is the number of distinct elements, however that case is also wrong since the min/max only works in one direction (think about if v = 5, mid = 4 and the lower part of the array is all fives).
EDIT:
Ok people think I'm bananas and scream O(log(n)) as soon as they see something that looks like binary search. Sorry for being unclear folks.
Let's talk about the code in the first posting I made (the solution by CTCI):
If we have an array looking like this: [-1, 0, 1, 2, 3, 4, 5, 6, 7, 8], actually an array looking like this: [-1,...,n-2] of size n, we know that there is not element that can match. However - the algorithm will visit all elements since the elements aren't unique. I dare you, run it, it can not divide the search space by 2 as in a regular binary search. Please tell me what is wrong with my reasoning.
No, in my opinion the first solution is not O(log n) as other answers state, it is really O(n) worst case (in the worst case it still needs to go through all the elements, consider equivalence array shifted by one as also mentioned by the author).
The cause why it is not O(log n) is because it needs to search on both sides of the middle (binary search only checks one side of middle therefore it is O(log n)).
It allows to skip items if you're lucky, however your second iterative solution skips items too if not needed to look on them (because you know there cannot be magic index in such range as the array is sorted) so in my opinion the second solution is better (the same complexity + iterative i.e. better space complexity and no recursive calls which are relatively expensive).
EDIT: However when I thought about the first solution again, it on the other side allows to also "skip backwards" if possible, which the iterative solution does not allow - consider for example an array like { -10, -9, -8, -7, -6, -5 } - the iterative solution would need to check all the elements, because it starts at the beginning and the values do not allow to skip forward, whereas when starting from the middle, the algo can completely skip checking the first half, then the first half of the second half, etc.
You are correct, the worst case complexity is O(n). You may have to visit all the elements of your array.
There is only one reason to not visit the array elements [mid, end] and that is when array[mid] > end (because in that case, the magic index is surely absent from [mid, end] elements).
Similarly, there is only one reason to not visit the array elements [start, mid] and that is when array[start] > mid.
So, there is a hope that you may not have to visit all the elements. Therefore it is one optimization which may work.
Thus, this binary-like method seems better than iterating over the entire array linearly but in worst case, you will hit O(n).
PS: I've assumed that array is sorted in ascending order.
It looks like you misunderstood the time complexity the required solution. The worse case is not O(n), it is O(log(n)). This is because during each pass you search next time only half of the array.
Here is a C++ example and check that for the whole array of 11 elements, it take only 3 checks.
Edit3: Optimized by limiting the initialization of the array to only odd numbers. Thank you #Ronnie !
Edit2: Thank you all, seems as if there's nothing more I can do for this.
Edit: I know Python and Haskell are implemented in other languages and more or less perform the same operation I have bellow, and that the complied C code will beat them out any day. I'm just wondering if standard C (or any libraries) have built-in functions for doing this faster.
I'm implementing a prime sieve in C using Eratosthenes' algorithm and need to initialize an integer array of arbitrary size n from 0 to n. I know that in Python you could do:
integer_array = range(n)
and that's it. Or in Haskell:
integer_array = [1..n]
However, I can't seem to find an analogous method implemented in C. The solution I've come up with initializes the array and then iterates over it, assigning each value to the index at that point, but it feels incredibly inefficient.
int init_array()
{
/*
* assigning upper_limit manually in function for now, will expand to take value for
* upper_limit from the command line later.
*/
int upper_limit = 100000000;
int size = floor(upper_limit / 2) + 1;
int *int_array = malloc(sizeof(int) * size);
// debug macro, basically replaces assert(), disregard.
check(int_array != NULL, "Memory allocation error");
int_array[0] = 0;
int_array[1] = 2;
int i;
for(i = 2; i < size; i++) {
int_array[i] = (i * 2) - 1;
}
// checking some arbitrary point in the array to make sure it assigned properly.
// the value at any index 'i' should equal (i * 2) - 1 for i >= 2
printf("%d\n", int_array[1000]); // should equal 1999
printf("%d\n", int_array[size-1]); // should equal 99999999
free(int_array);
return 0;
error:
return -1;
}
Is there a better way to do this? (no, apparently there's not!)
The solution I've come up with initializes the array and then iterates over it, assigning each value to the index at that point, but it feels incredibly inefficient.
You may be able to cut down on the number of lines of code, but I do not think this has anything to do with "efficiency".
While there is only one line of code in Haskell and Python, what happens under the hood is the same thing as your C code does (in the best case; it could perform much worse depending on how it is implemented).
There are standard library functions to fill an array with constant values (and they could conceivably perform better, although I would not bet on that), but this does not apply here.
Here a better algorithm is probably a better bet in terms of optimising the allocation:-
Halve the size int_array_ptr by taking advantage of the fact that
you'll only need to test for odd numbers in the sieve
Run this through some wheel factorisation for numbers 3,5,7 to reduce the subsequent comparisons by 70%+
That should speed things up.
I am actually trying to solve a problem where I have an array which is sorted but a few numbers are reversed . For example : 1 2 3 4 9 8 7 11 12 14 is the array.
Now , my first thought was applying a Binary Search algorithm to find a PEAK ( a[i]>a[i+1] && a[i]>a[i-1])
However , I feel it might not always give the correct result. Moreover it might not be efficient since the list is almost sorted.
Next impression : Applying Insertion Sort since the list is sorted and insertion sort gives best performance in such case IF I am not wrong.
So can anyone suggest better solutions or whether my solutions are correct or not? Efficient of In-efficient?
P.S - This is NOT homework !
UPDATE : Insertion Sort (O(n) in this case) or Linear Scan to find the subsequence and then reversing it (O(n)) again. Is there any chance if we could optimize it? Or probably do in O(logn) ?
Search linearly for the first inversion (i.e. a[i+1] < a[i]), call its index inv1. Continue until inversions stop, call the last index inv2. Reverse the array between inv1 and inv2, inclusive.
In your example, inv1 is 4, and inv2 is 6; array elements are numbered from zero.
The algorithm is linear in the number of entries in the original.
If you're sure that the list is sorted except for an embedded subsequence that is reversed, I suggest that you do a simple scan, detect the start of the reversed subsequence (by finding the first counter-directional change), scan to the end of the subsequence (where the changes resume the correct direction) and reverse the subsequence. This should also work for multiple subsequences provided they do not overlap. The complexity should be O(n).
Note: there should be an extra decision whether to cut between {4,9}, or between {9,8}. (I just add one ;-)
#include <stdio.h>
int array[] = {1,2,3,4,9,8,7,11,12,14};
unsigned findrev(int *arr, unsigned len, unsigned *ppos);
void revrev(int *arr, unsigned len);
unsigned findrev(int *arr, unsigned len, unsigned *ppos)
{
unsigned zlen,pos;
for(zlen=pos=0; pos < len-1; pos++ ) {
if (arr[pos+1] < arr[pos]) zlen++;
else if (zlen) break;
}
if (zlen) *ppos = pos - zlen++;
return zlen;
}
void revrev(int *arr, unsigned len)
{
unsigned pos;
for (pos = 0; pos < --len; pos++) {
int tmp;
tmp = arr[pos];
arr[pos] = arr[len] ;
arr[len] = tmp;
}
}
int main(void)
{
unsigned start,len;
len = findrev(array, 10, &start);
printf("Start=%u Len=%u\n", start, len);
revrev(array+start, len);
for (start=0; start < 10; start++) {
printf(" %d", array[start] );
}
printf("\n" );
return 0;
}
NOTE: the length of the reversed run could also be found by a binary-search for the first value larger (or equal) than the first element of the reversed sequence.
Timsort is quite good at sorting mostly-already-sorted arrays - on top of that, it does an in-place mergesort by using two different mergesteps depending on which will work better. I'm told it's found in the python and java standard libraries, perhaps others. You still probably shouldn't use it inside a loop though - inside a loop you're better off with a treap (for good average speed) or red-black tree (for low standard deviation speed).
I think linear solution [O(n)] is the best possible solution since in a list of n numbers, if n/2 numbers are reverse sorted as in example below we will have to invert n/2 numbers which gives complexity of O(n).
Also even in this case for a similar sequence, I think insertion sort will be O (n^2) and not O (n) in worst case.
Example: Consider an array with distribution below and we attempt to use insertion sort,
n/4 sorted numbers | n2 reverse sorted numbers | n/4 sorted numbers
For the n/2 reverse sorted numbers the sorting complexity will be O(n^2).
Our professor gave us the following assignment:
A "correct" series is one in which the sum of its members equals to the index of its first member.
The program is supposed to find the length of the LONGEST "correct" series within a series of n numbers.
For example: if the input series would be arr[4]={1, 1, 0, 0}
the output (longest "correct" series) would be 3.
arr[0]=1. 0!=1 therefore the longest series here is 0.
arr[1]=1,and 1=1. but the following members also sum up to 1 as shown below:
1=arr[1]+arr[2]+arr[3] = 1+ 0 + 0, therefore the longest series here is 3.
The output in this example is 3.
This is what I have so far:
int solve(int arr[], int index, int length,int sum_so_far)
{
int maxwith,maxwithout;
if(index==length)
return 0;
maxwith = 1+ solve(arr,index+1,length,sum_so_far+arr[index]);
maxwithout = solve(arr,index+1,length,arr[index+1]);
if(sum_so_far+arr[index]==index)
if(maxwith>maxwithout)
return maxwith;
return maxwithout;
return 0;
}
int longestIndex(int arr[], int index,int length)
{
return solve(arr,0,length,0);
}
What am I doing wrong here?
We aren't supposed to us loops on this assignment.
Hmm, there are several problems with this program.
Most obvious, "return maxwithout; return 0;" should give a compile error: There's no way to get to that last return statement.
Second, you're recursing in to solve on the "maxwith" path until you reach the end of the array. Then you're going to recurse into maxwithout, hitting it for the first time with index=4. I don't think this is going to work.
Frankly, I don't think this problem really calls for recursion. THe most natural solution would be a nested loop:
for (int start=0;start<length;++start)
{
for (int end=start;end<length;++end)
{
// calculate the sum of arr[start]->arr[end] and compare to start
}
}
Or something to that effect.
Did the problem call for solving it with recursion, or was that just your first idea at a good solution?
Edit
Okay, so you have to use recursion. I guess the point of the lesson is to learn to use recursion, not necessarily to solve the problem in the most natural or efficient way. (Personally, I think the teacher should have come up with a problem where recursion was a natural solution, but I guess we're not here to critique the teacher today.)
I don't want to do your homework for you, but I'll give you a hint. You can use recursion to simulate a loop by putting the break condition at the beginning of the function and putting the recursive call at the end of the function with a +1 parameter. That is, instead of writing
for (int x=0;x<10;++x) { ... whatever ...}
you can write
void forx(int x)
{
if (x>=10)
return;
... whatever ...
forx(x+1);
}
So in this case I'd do something like:
void endloop(int start, int end)
{
if (end>=arrayLength)
return;
... work on running total ...
endloop(start, end+1);
}
void startloop(int start)
{
if (start>=arrayLength)
return;
endloop(start, start);
}
int main()
{
... setup ...
startloop(0);
... output ...
}
Parameter lists are not necessarily complete. As I say, I don't want to do your homework for you, just give you a hint to get started.
First, write a function that tests a series of given starting index and given length for the "sum of its members" condition. Then, write a second function which looks for the longest series within your array where only the starting index is given (looping over the sub-series length in decreasing order should do it); this function can call the first one. At last, write a third function looping over all starting indexes, calling function number two.
Oh wait, there is no recursion needed any more, so a lot of brain-twisting is gone ... :-)
It seems to me that the problem lies here:
if(sum_so_far+arr[index]==index)
You're comparing the sum so far with the current index, but you should be comparing it with the first index in the series. It seems to me that it would be better if you started with the last element of arr towards the first, instead of going in the natural order. That way you start summing elements up until the sum equals the current index.