finding longest sequence of a particular value - algorithm

I want to find the longest sequence of a particular number i.e. 1 appearing in an array. Suppose the array is {1,0,0,0,1,1,1,1,0,0,1,1}; the answer should be 4 as one appears at most four times consecutively.

Use run length encoding.
In R, it's just
max(rle(x)$lengths)

Start with an array of numbers, A, find the longest
contiguous run of some number N in A.
Pseudo C...
MaxRun = 0 /* Longest run so far */
for (i = 0; i < length(A);) {
if A[i] = N {
/* Potential run of N's... */
/* Scan backward for first N in run */
for (j = i; j > 0 & A[j-1] = N; j--);
/* Scan forward to last N in run */
for (k = i; k < length(A)-1 & A[k+1] = N; k++);
/* Check to see if longer run found... */
if (k-j+1 > MaxRun) then MaxRun = k-j+1;
i = k /* jump i to last N found */
}
i = i + MaxRun + 1 /* Jump by longest run plus 1 */
}
MaxRun is the answer
The idea is that once you find a contiguous run of N's you can
jump ahead at least that far in the array before checking for
another candidate.
This algorithm has a possible sublinear run time because of the jump factor. Worst case is that every A[i] will be examined.

There will be more efficient methods, but this is what i got for now (C#):
int count = 0;
int maxCount = 0;
for (int i = 0; i < someArray.Count(); i++)
{
if (someArray[i] == 1)
{
count++;
}
else
{
if(count > maxCount)
{
maxCount = count;
}
count = 0;
}
}

A = array, L = its length
cnt = 0
max = 0
for i = 0 .. L - 1
if A[i] == 0
if (cnt > max) max = cnt
cnt = 0
else
cnt = cnt + 1
if (cnt > max) max = cnt

Here is another linear solution, idea is to maintain two runners. On the beginning boundary of 1 the 1st runner waits until 2nd runner has reached the end (i.e 0).
int i = 0, j= 0, max = 0, n = A.length;
while ( j < n ) {
if (j == (n-1)) { // reached boundary
j = ( A[j] == 1) ? j++ : j;
int k = j-i;
if ( k > max ) { max = k;}
}
else if ( A[j] == 1 ) { j++; }// increment 2nd runner
else {
int k = j-i;
if ( k > max ) { max = k;}
j++; i = j;
}
}
max is answer.

Related

Find zeroes to be flipped so that number of consecutive 1’s is maximized

Find zeroes to be flipped so that number of consecutive 1’s is maximized.
Input: arr[] = {1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1}
m = 2
Output: 5 7
We are allowed to flip maximum 2 zeroes. If we flip
arr[5] and arr[7], we get 8 consecutive 1's which is
maximum possible under given constraints .
Now if we were to find just the maximum number of 1's that is possible, is it possible to solve using dynamic programming approach?
This problem can be solved in linear time O(N) and linear space O(N). Its not full fledged dynamic programming, but its similar to that as it uses precomputation.
Data Structures Used:
1.left: It is an integer array, of same length as given array. It is precomputed such that for every position i:
left[i] = Number of consecutive 1's to the left position i
2.right: It is an integer array, of same length as given array. It is precomputed such that for every position i:
right[i] = Number of consecutive 1's to the right position i
These can be computed in single traversal of the array.Assuming arr is the original array, following pseudocode does the job:
Pseudocode for populating left array
left()
{
int count = 0;
for(int i = 0;i < arr length; ++i)
{
if(i == 0)
{
left[i] = 0;
if(arr[i] == 1)
count++;
continue;
}
else
{
left[i] = count;
if(arr[i] == 1)
count++;
else count = 0;
}
}
}
Pseudocode for populating right array
right()
{
int count = 0;
for(int i = arr length - 1;i >= 0; --i)
{
if(i == arr length - 1)
{
right[i] = 0;
if(arr[i] == 1)
count++;
continue;
}
else
{
right[i] = count;
if(arr[i] == 1)
count++;
else count = 0;
}
}
}
Now the only thing we have to do is :check all pair of positions i and j (i < j) such that arr[i] = 0 and arr[j] = 0 and for no position between i and j arr[i] should be 0 and Keep track of the pair for which we get maximum value of the following:
left[i] + right[j] + right[l]
You could also use left[i] + right[j] + left[r].
left[i] tells the number of consecutive 1's to the left of position i and right[j] tells the number of consecutive 1's to the right of position j and the number of consecutive 1's between i and j can be counted be left[r] OR right[l], and therefore, we have two candidate expressions.
This can also be done in single traversal, using following pseudocode:
max_One()
{
max = 0;
l = -1, r = -1;
for(int i = 0;i < arr length; ++i)
{
if(arr[i] == 0)
{
if(l == -1)
l = i;
else
{
r = i;
if(left[l] + right[r] + right[l] > max)
{
max = left[l] + right[r] + right[l];
left_pos = l;
right_pos = r;
}
l = r;
}
}
}
}
You should use sliding window concept here - use start and end vars to store index of range. Whenever you encounter a 0, increment the counter of zeros received. Include it in current length.. If zeros encounter equals m+1, increment start till you encounter 0.
public static int[] zerosToFlip(int[] input, int m) {
if (m == 0) return new int[0];
int[] indices = new int[m];
int beginIndex = 0;
int endIndex = 0;
int maxBeginIndex=0;
int maxEndIndex=0;
int zerosIncluded = input[0] == 0 ? 1 : 0;
for (int i = 1; i < input.length; i++) {
if (input[i] == 0) {
if (zerosIncluded == m) {
if (endIndex - beginIndex > maxEndIndex - maxBeginIndex){
maxBeginIndex = beginIndex;
maxEndIndex = endIndex;
}
while (input[beginIndex] != 0) beginIndex++;
beginIndex++;
} else {
zerosIncluded++;
}
}
endIndex++;
}
if (endIndex - beginIndex > maxEndIndex - maxBeginIndex){
maxBeginIndex = beginIndex;
maxEndIndex = endIndex;
}
int j = 0;
for (int i = maxBeginIndex; i <= maxEndIndex; i++) {
if (input[i] == 0) {
indices[j] = i;
++j;
}
}
return indices;
}

Longest slice of a binary array that can be split into two parts

how to find longest slice of a binary array that can be split into two parts: in the left part, 0 should be the leader; in the right part, 1 should be the leader ?
for example :
[1,1,0,1,0,0,1,1] should return 7 so that the first part is [1,0,1,0,0] and the second part is [1,1]
i tried the following soln and it succeeds in some test cases but i think it is not efficient:
public static int solution(int[] A)
{
int length = A.Length;
if (length <2|| length>100000)
return 0;
if (length == 2 && A[0] != A[1])
return 0;
if (length == 2 && A[0] == A[1])
return 2;
int zerosCount = 0;
int OnesCount = 0;
int start = 0;
int end = 0;
int count=0;
//left hand side
for (int i = 0; i < length; i++)
{
end = i;
if (A[i] == 0)
zerosCount++;
if (A[i] == 1)
OnesCount++;
count = i;
if (zerosCount == OnesCount )
{
start++;
break;
}
}
int zeros = 0;
int ones = 0;
//right hand side
for (int j = end+1; j < length; j++)
{
count++;
if (A[j] == 0)
zeros++;
if (A[j] == 1)
ones++;
if (zeros == ones)
{
end--;
break;
}
}
return count;
}
I agree brute force is time complexity: O(n^3).
But this can be solved in linear time. I've implemented it in C, here is the code:
int f4(int* src,int n)
{
int i;
int sum;
int min;
int sta;
int mid;
int end;
// Find middle
sum = 0;
mid = -1;
for (i=0 ; i<n-1 ; i++)
{
if (src[i]) sum++;
else sum--;
if (src[i]==0 && src[i+1]==1)
{
if (mid==-1 || sum<min)
{
min=sum;
mid=i+1;
}
}
}
if (mid==-1) return 0;
// Find start
sum=0;
for (i=mid-1 ; i>=0 ; i--)
{
if (src[i]) sum++;
else sum--;
if (sum<0) sta=i;
}
// Find end
sum=0;
for (i=mid ; i<n ; i++)
{
if (src[i]) sum++;
else sum--;
if (sum>0) end=i+1;
}
return end-sta;
}
This code is tested: brute force results vs. this function. They have same results. I tested all valid arrays of 10 elements (1024 combinations).
If you liked this answer, don't forget to vote up :)
As promissed, heres the update:
I've found a simple algorithm with linear timecomplexity to solve the problem.
The math:
Defining the input as int[] bits, we can define this function:
f(x) = {bits[x] = 0: -1; bits[x] = 1: 1}
Next step would be to create a basic integral of this function for the given input:
F(x) = bits[x] + F(x - 1)
F(-1) = 0
This integral is from 0 to x.
F(x) simply represents the number of count(bits , 1 , 0 , x + 1) - count(bits , 0 , 0 , x + 1). This can be used to define the following function: F(x , y) = F(y) - F(x), which would be the same as count(bits , 1 , x , y + 1) - count(bits , 0 , x , y + 1) (number of 1s minus number of 0s in the range [x , y] - this is just to show how the algorithm basically works).
Since the searched sequence of the field must fulfill the following condition: in the range [start , mid] 0 must be leading, and in the range [mid , end] 1 must be leading and end - start + 1 must be the biggest possible value, the searched mid must fulfill the following condition: F(mid) < F(start) AND F(mid) < F(end). So first step is to search the minimum of 'F(x)', which would be the mid (every other point must be > than the minimum, and thus will result in a smaller / equally big range [end - start + 1]. NOTE: this search can be optimized by taking into the following into account: f(x) is always either 1 or -1. Thus, if f(x) returns 1bits for the next n steps, the next possible index with a minimum would be n * 2 ('n' 1s since the last minimum means, that 'n' -1s are required afterwards to reach a minimum - or atleast 'n' steps).
Given the 'x' for the minimum of F(x), we can simply find start and end (biggest/smallest value b, s ∈ [0 , length(bits) - 1] such that: F(s) > F(mid) and F(b) > F(mid), which can be found in linear time.
Pseudocode:
input: int[] bits
output: int
//input verification left out
//transform the input into F(x)
int temp = 0;
for int i in [0 , length(bits)]
if bits[i] == 0
--temp;
else
++temp;
//search the minimum of F(x)
int midIndex = -1
int mid = length(bits)
for int i in [0 , length(bits - 1)]
if bits[i] > mid
i += bits[i] - mid //leave out next n steps (see above)
else if bits[i - 1] > bits[i] AND bits[i + 1] > bits[i]
midIndex = i
mid = bits[i]
if midIndex == -1
return //only 1s in the array
//search for the endindex
int end
for end in [length(bits - 1) , mid]
if bits[end] > mid
break
else
end -= mid - bits[end] //leave out next n searchsteps
//search for the startindex
int start
for start in [0 , mid]
if bits[start] > mid
break
else
start += mid - bits[start]
return end - start

Find number of bits to be flipped to get maximum 1's in array

We have a bit array like below
{1 0 1 0 0 1 0 1}
Number of bits in above array is 8
If we take range from [1,5] then number of bits in [1,5] range is [0 1 0 0 1].
If we flip this range then after flipping it will be [ 1 0 1 1 0]
So total number of 1's after flipping [1,5] range is [1 1 0 1 1 0 0 1] = 5
If we take range from [1,6] then number of bits in [1,6] range is [0 1 0 0 1 0].
If we flip this range then after flipping it will be [ 1 0 1 1 0 1]
So total number of 1's after flipping [1,5] range is [1 1 0 1 1 0 1 1] = 6
So the answer is range [1,6] and after flipping we can get 6 1's in array
Is there a good algorithm that can solve this problem. I an only think of dynamic programming because this problem can be broken down into sub problems which can be combined.
Inspired by #Nabbs comment, there is an easy way to solve this in linear time: by reducing the problem to maximal segment sum.
Transform all 0s to 1s and all 1s to -1s. The problem is then the same as minimizing the sum of the array after transforming. (the minimal sum contains most -1s in the transformed array, which corresponds to most 1s in the original problem).
We can calculate the sum as
sum(after flipping) = sum(non-flipped) - sum(flipped part before flipping)
because the sum of the flipped part is inverted. If we now express the non-flipped part as follows:
sum(non-flipped) = sum(original array) - sum(flipped part before flipping)
we find that we need to minimize
sum(after flipping) = sum(original array) - 2 sum(flipped part before flipping)
The first part is a constant, so we really need to maximize the sum of the flipped part. This is exactly what the maximum segment sum problem does.
I wrote a lengthy derivation on how to solve that problem in linear time a while ago, so now I'll only share the code. Below I updated the code to also store the boundaries. I chose javascript as the language, because it is so easy to test in the browser and because I don't have to make the types of variables x and y explicit.
var A = Array(1, 0, 1, 0, 0, 1, 0, 1);
var sum = 0;
// count the 1s in the original array and
// do the 0 -> 1 and 1 -> -1 conversion
for(var i = 0; i < A.length; i++) {
sum += A[i];
A[i] = A[i] == 0 ? 1 : -1;
}
// find the maximum subarray
var x = { value: 0, left: 0, right: 0 };
var y = { value: 0, left: 0 };
for (var n = 0; n < A.length; n++) {
// update y
if (y.value + A[n] >= 0) {
y.value += A[n];
} else {
y.left = n+1;
y.value = 0;
}
// update x
if (x.value < y.value) {
x.left = y.left;
x.right = n;
x.value = y.value;
}
}
// convert the result back
alert("result = " + (sum + x.value)
+ " in range [" + x.left + ", " + x.right + "]");
You can easily verify this in your browser. For instance in Chrome, press F12, click Console and paste this code. It should output
result = 6 in range [1, 4]
The solution uses Kadane's Algorithm.
We have to pick that substring where there are maximum number of 0s and minimum number of 1s, i.e., substring with max(count(0)-count(1)). So that after the flip, we can get maximum number of 1s in the final string.
Iterate over the string and keep a count. Increment this count whenever we encounter a 0 and decrement it when we encounter 1. The substring which will have the maximum value of this count will be our answer.
Here's a video by alGOds which explains the approach nicely. Do watch it if you have any doubts.
Link : https://youtu.be/cLVpE5q_-DE
The following code uses the trivial algorithm and runs in O(n²).
#include <iostream>
#include <bitset>
#include <utility>
typedef std::pair<unsigned, unsigned> range_t;
template <std::size_t N>
range_t max_flip(const std::bitset<N>& bs){
int overall_score = 0;
range_t result = range_t{0,0};
for(std::size_t i = 0; i < N; ++i){
int score = bs[i] ? -1 : 1;
auto max = i;
for(std::size_t j = i + 1; j < N; ++j){
auto new_score = score + (bs[j] ? -1 : 1);
if(new_score > score){
score = new_score;
max = j;
}
}
if(score > overall_score){
overall_score = score;
result = {i,max};
}
}
return result;
}
int main(){
std::bitset<8> bitfield(std::string("10100101"));
range_t range = max_flip(bitfield);
std::cout << range.first << " .. " << range.second << std::endl;
}
Attempt 2.0 in O(n)
Start at the beginning of the array. Step through the array. Until you reach a 0. When you reach the first 0, set count to 0, remember the start position and continue stepping while counting: +1 for 0 and -1 for 1. If the count becomes negative, reset the count and continue until you reach the end. If you find another zero set count to 0 and repeat the previous algorithm. At the end you flip the range of the start and end position if there is one.
void Flip( int* arr , int len )
{
int s = -1 , e = -1 , c ;
for( int i = 0 ; i < len ; i++ )
{
if( arr[i] == 0 )
{
c = 0 ;
s = i ;
e = i ;
for( int j = i ; j < len ; j++ , i++ )
{
if( arr[i] == 0 )
c++ ;
else
c-- ;
if( c < 0 )
{
s = -1 ;
e = -1 ;
break ;
}
if( arr[i] == 0 )
e = i ;
}
}
}
if( s > -1 )
for( int i = s ; i <= e ; i++ )
arr[i] ^= 1 ;
for( int i = 0 ; i < len ; i++ )
printf("%d " , arr[i] ) ;
}
int main(void)
{
int a[13] = {1,0,1,1,0,0,1,0,1,1,0,1,0} ;
Flip( a , 13 ) ;
return 0;
}
Not thoroughly tested, there may be bugs( edge cases ) but it works in principle.
void maxones(int n)
{
int table[n+1][n+1], i, j, totalones = 0, max = INT_MIN, start_pos = 0, end_pos =0;
if(n == 0)
{
printf("Max no of ones from 0 to %d \n",sizeof(int) * 8 -1);
return;
}
/* size of (int) * 8 bits, calculate total no of ones in every bit */
for(i=0; i<sizeof(n) * 8; i++)
totalones += n & (1 >> i);
/* Base conditions to be filled */
for(i=0; i<n; i++)
table[i][i] = (n & (1 >> i)) ? totalones - 1 : totalones + 1;
for(i=0; i<n; i++ )
for(j=i+1; j<n; j++)
{
table[i][j] = table[i][j-1] + ( n & (1 >> j)) ? 0 : 1;
if (max < table[i][j])
{
max = table[i][j];
start_pos = i;
end_pos = j;
}
}
printf("Max no of Ones on fliping bits from pos %d to pos %d \n",start_pos, end_pos);
}
int main()
{
int n;
printf("Enter number %d \n", &n);
maxones(n);
return 0;
}
Here is a recursive approach:
https://ideone.com/Su2Mmb
public static void main(String[] args) {
int [] input = {1, 0, 0, 1, 0, 0, 1,1,1,1, 0,1};
System.out.println(findMaxNumberOfOnes(input,0, input.length-1));
}
private static int findMaxNumberOfOnes(int[] input, int i, int j) {
if (i==j)
return 1;
int option1 = input[i] + findMaxNumberOfOnes(input, i+1, j);
int option2 = count(input , i , j, true);
int option3 = count(input, i, j, false);
int option4 =findMaxNumberOfOnes(input, i, j-1) +input[j];
return Math.max(option1, Math.max(option2,Math.max(option3,option4)));
}
private static int count(int[] input, int i, int j, boolean flipped) {
int a = flipped?0:1;
int count = 0;
while (i<=j){
count += (input[i++]==a)?1:0;
}
return count;
}
This problem can be solved using dynamic programming in linear time and space. You can create an array left where left[i] is the number of 1 on subarray 0 to i (inclusive). So for two index i and j:
case 1: i==j, result is array size sz-1 (if no 0 in array) or sz+1 (if there is at least one 0 in array)
case 2: i less than j, result is:
left[i-1] (# of 1 on subarray 0 ~ i-1) +
(j-i+1-(left[j]-left[i-1])) (# of 0 on subarray i ~ j) +
left[sz-1]-left[j] (# of 1 on subarray j+1 ~ sz-1)
this equals to: (j-2*left[j])-(i-2*left[i-1])+left[sz-1]+1
So according to case 2, we need another array temp to store for every j min{i-2*left[i-1] where i<j}
So we can traverse the array, at each index j, we calculate the above case two (in constant time) and update final result if it's larger.
My code in c++:
int func(vector<int>& arr){
int res = 0;
int sz = arr.size();
vector<int> left(sz, 0);
for(int i=0; i<sz; i++){
left[i] = (arr[i]==1?1:0)+(i==0?0:left[i-1]);
}
bool all_1 = true;
for(int i=0; i<sz; i++){
if(arr[i] == 0) all_1=false;
}
if(all_1) return sz-1;
res = left[sz-1]+1;
vector<int> temp(sz, INT_MAX);
for(int i=1; i<sz; i++)
temp[i] = min(temp[i-1], i-2*left[i-1]);
for(int j=1; j<sz; j++){
int val = j+1-left[j]+(left[sz-1]-left[j]);
val = max(val, j-2*left[j]-temp[j]+left[sz-1]+1);
res = max(res, val);
}
return res;
}
I also thought the same way as #this has mentioned. But there are bugs in his solution. My code after fixing the bug(see explanation below):
vector<int> Solution::flip(string arr) {
int s = -1 , e = -1 , c , len = arr.size(), S = -1, E = -1, Max = 0;
for( int i = 0 ; i < len ; i++ )
{
if( arr[i] == '0' )
{
c = 0 ;
s = i ;
e = i ;
for( int j = i ; j < len ; j++, i++ )
{
if( arr[j] == '0' )
c++ ;
else
c-- ;
//cout << c << " ";
if( c < 0 )
{
s = -1 ;
e = -1 ;
break ;
}
if( arr[j] == '0' )
e = i ;
if(c > Max){
S = s;
E = e;
Max = c;
}
}
}
}
vector<int> ans;
if( S > -1 ){
ans.push_back(S);
ans.push_back(E);
return ans;
}
else
return ans;
}
Explanation:
Start at the beginning of the array. Step through the array. Until you reach a 0. When you reach the first 0, set count to 0, remember the start position and continue stepping while counting: +1 for 0 and -1 for 1.Max stores the value of max(#zeros in all set of [s, e]). If c becomes greater than Max then the current set [s, e] contains the maximum number of '0' bits. Hence update Max, S, E,. If the count becomes negative, it means the number of '1' is greater then number of '0' in set [s, e], so reset the count c, local start s, local end e. and continue until you reach the end. If you find another zero set count to 0 and repeat the previous algorithm. The final value of S, E are the index of the range in which bits are to be flipped. If no such range exist(all bits are '1') then S = -1, E = - 1.
This Solution is also inspired by #Nabb's comment. I have created a new array with 0 replaced as 1 and 1 as -1. Then I used maximum subarray sum range problem's concept to solve it. The code is as below:
vector<int> Solution::flip(string A) {
vector<int> vec;
vector<int> res;
for(int i=0;i<A.length();i++){
if(A[i]=='1')
vec.push_back(-1);
else
vec.push_back(1);
}
int l=0,r=0,s=0;
int sum=0;
int sum_prev=INT_MIN;
for(int i=0;i<vec.size();i++){
sum+=vec[i];
if(sum_prev<sum){
sum_prev=sum;
l=s;
r=i;
}
if(sum<0){
sum=0;
s=i+1;
}
}
//cout<<"l: "<<l<<" r: "<<r<<endl;
if((l>=0 && r>0)||((l==0 && r==0) && A[0]=='0')){
res.push_back(l+1);
res.push_back(r+1);
}
return res;
}
Let me provide the solution and it is actually based on the Kadane's Algorithm.
The code is a bit long but most of them are comments written by me to help you understand a bit more.
Space complexity: O(1)
Time complexity: O(n)
# flip to zero to get max one
def flip_zero(nums):
# max number of 0 at index and global
max_nums_at_index, max_nums_global = None, None
start, end = None, None
for i in range(len(nums)):
if i == 0:
if nums[i] == 0:
# In position 0, if the digit is 0, then the count of zero will be 1
max_nums_at_index, max_nums_global = 1, 1
else:
# In position 0, if the digit is 1, then the count of zero will be 0
max_nums_at_index, max_nums_global = 0, 0
# Mark the start and end position of the substring
start, end = i, i
else:
# In other position, we need to consider we are going to added it or not
if nums[i] == 0:
# If the number is 0, then after we included it the count of zero will be increased by 1
# If we don't add it and means we will start a new subarray from current index
# the count of zero at current index will be 1
# So here we need to do comparison and see which one is bigger.
max_nums_at_index = max(max_nums_at_index + 1, 1)
# Check whether we start a new sub array, if yes, update the start index
if max_nums_at_index == 1:
start = i
else:
# If the number is 1, then after we include it the count of zero will remain unchange
# If we don't add it and means we will start a new array from current index
# the count of zero at current index will be 0
# So here we need to do comparison and see which one is bigger.
max_nums_at_index = max(max_nums_at_index, 0)
# Check whether we start a new sub array, if yes, update the start index
if max_nums_at_index == 0:
start = i
temp = max_nums_global
max_nums_global = max(max_nums_global, max_nums_at_index)
# Check whether the global max has been updated, if yes, update the end index
if max_nums_global != temp:
end = i
return [start, end]
And the result return is [1, 6]
It is possible even much more simple. See this python example O (n):
def flipBits_for_maximum_1s (a, n):
countOfOnes = 0
# find contiguous subarray with biggest sum
# of 'count of 0s' - 'count of 1s'
big = cur_big = 0
for x in a:
if x:
countOfOnes += 1
cur_big -= 1
else: cur_big += 1
if cur_big > big: big = cur_big
if (cur_big < 0): cur_big = 0;
return big + countOfOnes

Sorting in linear time and in place

Suppose that n records have keys in the range from 1 to k.
Write an algorithm to sort the records in place in O(n+k) time.
You may use O(k) storage outside the input array.
Is your algorithm stable?
if we use counting sort to we can do it in O(n+k) time and is stable but its not in place.
if k=2 it can be done in place but its not stable (using two variables to maintain the indexes in the array for k=0 and k=1)
but for k>2 i couldnt think of any good algo
First, let's rehash how counting sort works:
Count how often every key exists in the array to be sorted. These counts are written to an array of size k.
Compute the partial sums of the key counts. This gives the starting position for every bin of equal keys in the sorted array.
Move the items in the array to their final position incrementing the starting position of the corresponding bin for every item.
Now the question is how to perform the final step in-place. The standard approach for an in-place permutation is to select the first element and swap it with the element that takes its correct position. This step is repeated with the swapped element until we hit a element that belongs in the first position (a cycle has been completed). Then the whole procedure is repeated for the elements at the second, third, etc. position until the whole array has been processed.
The problem with counting sort is that the final positions are not readily available but are computed by incrementing every bin's starting position in the final loop. In order to never increment the starting position twice for an element, we have to find a way to determine if an element at a certain position has been moved there already. This can be done by keeping track of the original starting position for every bin. If an element lies between the original starting position and the position for the next element of a bin, it has been already touched.
Here's an implementation in C99 that runs in O(n+k) and requires only two arrays of size k as extra storage. The final permutation step is not stable.
#include <stdlib.h>
void in_place_counting_sort(int *a, int n, int k)
{
int *start = (int *)calloc(k + 1, sizeof(int));
int *end = (int *)malloc(k * sizeof(int));
// Count.
for (int i = 0; i < n; ++i) {
++start[a[i]];
}
// Compute partial sums.
for (int bin = 0, sum = 0; bin < k; ++bin) {
int tmp = start[bin];
start[bin] = sum;
end[bin] = sum;
sum += tmp;
}
start[k] = n;
// Move elements.
for (int i = 0, cur_bin = 0; i < n; ++i) {
while (i >= start[cur_bin+1]) { ++cur_bin; }
if (i < end[cur_bin]) {
// Element has already been processed.
continue;
}
int bin = a[i];
while (bin != cur_bin) {
int j = end[bin]++;
// Swap bin and a[j]
int tmp = a[j];
a[j] = bin;
bin = tmp;
}
a[i] = bin;
++end[cur_bin];
}
free(start);
free(end);
}
Edit: Here's another version using only a single array of size k based on Mohit Bhura's approach.
#include <stdlib.h>
void in_place_counting_sort(int *a, int n, int k)
{
int *counts = (int *)calloc(k, sizeof(int));
// Count.
for (int i = 0; i < n; ++i) {
++counts[a[i]];
}
// Compute partial sums.
for (int val = 0, sum = 0; val < k; ++val) {
int tmp = counts[val];
counts[val] = sum;
sum += tmp;
}
// Move elements.
for (int i = n - 1; i >= 0; --i) {
int val = a[i];
int j = counts[val];
if (j < i) {
// Process a fresh cycle. Since the index 'i' moves
// downward and the counts move upward, it is
// guaranteed that a value is never moved twice.
do {
++counts[val];
// Swap val and a[j].
int tmp = val;
val = a[j];
a[j] = tmp;
j = counts[val];
} while (j < i);
// Move final value into place.
a[i] = val;
}
}
free(counts);
}
Here is my code that runs in O(n+k) time and uses only 1 extra array of size k ( apart from the main array of size n)
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char const *argv[])
{
int n = atoi(argv[1]);
int k = atoi(argv[2]);
printf("%d\t%d",n,k);
int *a,*c;
int num,index,tmp,i;
a = (int*)malloc(n*sizeof(int));
c = (int*)calloc(k,sizeof(int));
srand(time(NULL));
for(i=0;i<n;i++)
{
num = (rand() % (k));
a[i] = num;
c[num]++;
}
printf("\n\nArray is : \n");
for(i=0;i<n;i++)
{
printf("\t%d",a[i]);
if(i%8==7)
printf("\n");
}
printf("\n\nCount Array is : \n");
for(i=0;i<k;i++)
{
printf("\t%d(%d)",c[i],i);
if(i%8==7)
printf("\n");
}
//Indexing count Array
c[0]--;
for(i=1;i<k;i++)
{
c[i] = c[i-1] + c[i];
}
printf("\n\nCount Array After Indexing is : \n");
for(i=0;i<k;i++)
{
printf("\t%d(%d)",c[i],i);
if(i%8==7)
printf("\n");
}
// Swapping Elements in Array
for(i=0;i<n;i++)
{
index = c[a[i]];
//printf("\na[%d] = %d, going to position %d",i,a[i],index);
c[a[i]]--;
if(index > i)
{
tmp = a[i];
a[i] = a[index];
a[index] = tmp;
i--;
}
}
printf("\n\n\tFinal Sorted Array is : \n\n");
for(i=0;i<n;i++)
{
printf("\t%d",a[i]);
if(i%8==7)
printf("\n");
}
printf("\n\n");
return 0;
}
Even this algo is not stable. All elements are in their reverse order.
P.s : keys are in the range 0 to (k-1)
An example for integer valued sequences. The sort is unstable. While it is not as concise as the answer provided by Mohit it is marginally faster (for the common case where k << n) by skipping elements already in their correct bins (time is asymptotically the same). In practice I prefer Mohit's sort for its tighter, simpler loop.
def sort_inplace(seq):
min_ = min(seq)
max_ = max(seq)
k = max_ - min_ + 1
stop = [0] * k
for i in seq:
stop[i - min_] += 1
for j in range(1, k):
stop[j] += stop[j - 1]
insert = [0] + stop[:k - 1]
for j in range(k):
while insert[j] < stop[j] and seq[insert[j]] == j + min_:
insert[j] += 1
tmp = None
for j in range(k):
while insert[j] < stop[j]:
tmp, seq[insert[j]] = seq[insert[j]], tmp
while tmp is not None:
bin_ = tmp - min_
tmp, seq[insert[bin_]] = seq[insert[bin_]], tmp
while insert[bin_] < stop[bin_] and seq[insert[bin_]] == bin_ + min_:
insert[bin_] += 1
With a tighter loop but still skipping already-relocated elements:
def dave_sort(seq):
min_ = min(seq)
max_ = max(seq)
k = max_ - min_ + 1
stop = [0] * k
for i in seq:
stop[i - min_] += 1
for i in range(1, k):
stop[i] += stop[i-1]
insert = [0] + stop[:k - 1]
for meh in range(0, k - 1):
i = insert[meh]
while i < stop[meh]:
bin_ = seq[i] - min_
if insert[bin_] > i:
tmp = seq[insert[bin_]]
seq[insert[bin_]] = seq[i]
seq[i] = tmp
insert[bin_] += 1
else:
i += 1
Edit: Mohit's approach in Python with extra bits to verify the effect on stability of the sort.
from collections import namedtuple
from random import randrange
KV = namedtuple("KV", "k v")
def mohit_sort(seq, key):
f = lambda v: getattr(v, key)
keys = map(f, seq)
min_ = min(keys)
max_ = max(keys)
k = max_ - min_ + 1
insert = [0] * k
for i in keys:
insert[i - min_] += 1
insert[0] -= 1
for i in range(1, k):
insert[i] += insert[i-1]
i = 0
n = len(seq)
while i < n:
bin_ = f(seq[i])
if insert[bin_] > i:
seq[i], seq[insert[bin_]] = seq[insert[bin_]], seq[i]
i -= 1
insert[bin_] -= 1
i += 1
def test(n, k):
seq = []
vals = [0] * k
for _ in range(n):
key = randrange(k)
seq.append(KV(key, vals[key]))
vals[key] += 1
print(seq)
mohit_sort(seq, "k")
print(seq)
if __name__ == "__main__":
test(20, 3)
I really don't know why all the source codes posted here are so unnecessarily compilcated.
Here is a python solution:
def inplaceCtsort(A):
b, e = min(A), max(A)
nelems = e - b + 1
CtsBeforeOrIn = [0]*nelems
for i in A:
CtsBeforeOrIn[i-b] += 1
for i in range(1, nelems):
CtsBeforeOrIn[i] += CtsBeforeOrIn[i-1]
for i in range(0, len(A)):
while i < CtsBeforeOrIn[A[i]-b] - 1:
validPosition = CtsBeforeOrIn[A[i]-b] - 1
A[i], A[validPosition] = A[validPosition], A[i]
CtsBeforeOrIn[A[i]-b] -= 1

How many possible scorecards are consistent with the input scorecard?

I have been trying to solve the following problem in interview street. Count Scorecards(30 points)
In a tournament, N players play against each other exactly once. Each game results in either of the player winning. There are no ties. You have given a scorecard containing the scores of each player at the end of the tournament. The score of a player is the total number of games the player won in the tournament. However, the scores of some players might have been erased from the scorecard. How many possible scorecards are consistent with the input scorecard?
Input:
The first line contains the number of cases T. T cases follow. Each case contains the number N on the first line followed by N numbers on the second line. The ith number denotes s_i, the score of the ith player. If the score of the ith player has been erased, it is represented by -1.
Output:
Output T lines, containing the answer for each case. Output each result modulo 1000000007.
Constraints:
1 <= T <= 20
1 <= N <= 40
-1 <= s_i < N
Sample Input:
5
3
-1 -1 2
3
-1 -1 -1
4
0 1 2 3
2
1 1
4
-1 -1 -1 2
Sample Output:
2
7
1
0
12
Explanation:
For the first case, there are 2 scorecards possible: 0,1,2 or 1,0,2.
For the second case, the valid scorecards are 1,1,1, 0,1,2, 0,2,1, 1,0,2, 1,2,0, 2,0,1, 2,1,0.
For the third case, the only valid scorecard is {0,1,2,3}.
For the fourth case, there is no valid scorecard. It is not possible for both players to have score 1.
I have tried to come up with generic functions approach, but i am really trying to nail down this problem using Dynamic programming. How can you think of recurrence relations for this problem?.
Here is the DP solution to the above problem
public static int[][] table; // stores the result of the overlapping sub problems
private static int N;
public static void main(String args[]) {
Scanner scanner = new Scanner(System.in);
int testCases = scanner.nextInt();
for (int i = 0; i < testCases; i++) {
N = scanner.nextInt();
int[] scores = new int[N];
for (int j = 0; j < N; j++) {
scores[j] = scanner.nextInt();
}
long result = process(scores) % 1000000007L;
System.out.println(result );
}
}
private static long process(int[] scores) {
int sum = 0;
int amongPlayers = 0; //count no of players whose score has been erased(-1)
for (int i = 0; i < N; i++) {
if (scores[i] != -1) {
sum += scores[i];
} else {
amongPlayers++;
}
}
int noGames = (N * (N -1)) /2; // total number of games
if (sum < noGames) {
int distribute = noGames - sum; // score needed to be distributed;
table = new int[distribute + 1 ][amongPlayers + 1];
for (int m = 0; m <= distribute; m++) {
for (int n = 0; n <= amongPlayers; n++) {
table[m][n] = -1;
}
}
return distribute(distribute, amongPlayers); // distrubute scores among players whose score is erased(-1)
}
else if(sum == noGames){
return 1;
}
return 0;
}
/**
* Dynamic programming recursive calls
* #param distribute
* #param amongPlayers
* #return
*/
private static int distribute(int distribute, int amongPlayers) {
if(distribute == 0 && amongPlayers == 0)
return 1;
if (amongPlayers <= 0)
return 0;
if(distribute == 0)
return 1;
int result = 0;
if (table[distribute][amongPlayers - 1] == -1) {
int zeroResult = distribute(distribute, amongPlayers - 1);
table[distribute][amongPlayers - 1] = zeroResult;
}
result += table[distribute][amongPlayers - 1];
for (int i = 1; i < N ; i++) { // A person could win maximum of N-1 games
if (distribute - i >= 0) {
if (table[distribute - i][amongPlayers - 1] == -1) {
int localResult = distribute(distribute - i,
amongPlayers - 1);
table[distribute - i][amongPlayers - 1] = localResult;
}
result += table[distribute - i][amongPlayers - 1];
}
}
return result;
}
Observations:
Sequence s[1], s[2], ..., s[n] to be consistent scorecard, these properties must hold:
s[i1] + s[i2] + .. + s[ik] >= k * (k — 1) / 2, where i1 < i2 < .. < ik (i.e for every subsequences of length k)
s[1] + s[2] + .. + s[n] = n * (n — 1) / 2
First of all we need to check not erased scores, just using 1 condition. Then put erased scores using dynamic programming.
Let's denote erased scores b[i], not erased scores a[i];
sum{i = 1 .. l} a[i] + sum{i = 1 .. k} b[i] >= (k + l) * (k + l - 1) / 2
sum{i = 1 .. l} a[i] + sum{i = 1 .. k} b[i] >= 0 + 1 + .. + (k + l - 1)
sum{i = 1 .. l} (a[i] - (k + i - 1)) + sum{i = 1 .. k} b[i] >= 0 + 1 + .. + (k - 1)
So we can pre calculate for every k, minimal value of sum{i = 1 .. l} (a[i] - (k + i - 1))/
Dynamic programming:
states:
dp[k][score][sum]: we know first k minimum erased scores, and their values not exceeds $score$, and sum is their sum.
transitions:
Skip score, dp[k][score][sum] += dp[k][score + 1][sum];
Put $i$ scores of value $score$ dp[k][score][sum] += C[m — k][i] * dp[k + i][score + 1][sum + i*score], where m number of erased scores, C[n][k] = combination.
my code
The total sum of the wins should be (N C 2)
Subtract the known values which are given in the input. Let the remaining sum (N C 2) - x be called S. Let the number of -1's in the input be Q.
The problem now boils down to finding the number of integral solutions of Q variables ranging from 0 to N-1 (max score possible) and sum of which is S
Let DP[q][s] denote the number of integral solutions of q variables whose sum is s
Then we have,
DP[q][s] = Sum (i=0 to N-1) DP[q-1][s-i]
DP[Q][S] gives the solution
EDIT:
Observation:
For x people remaining, the number of total wins should be at least x*(x-1)/2 (when they play each other). Thus, at any time for q people, s cannot exceed (N-q)(N-q-1)/2 = M
There should be one more constraint that DP[q][s] should be equal to 0 when s is greater than M
I'm trying to solve this assignment, too, and think it should be something like this:
The number of players (=N), the number of unknown cards (count the "-1") and the sum of the known cards (count all cards except "-1") are given. The total number of games possible should be 1 +2 +3 + ... + (players-1): The first player has (players-1) opponents, the second player (players-2) etc.
Now you can recursively calculate the sum of possible score cards:
Initialize an empty hashmap with (players, unknown cards, sum of known cards) as the key and the sum of possible score cards as the value.
If all cards are defined, then the answer is either 0 (if the sum of all cards equals the total number of games possible) or 1 (if the sum of all cards does not equal the total number of games possible).
If not all cards are defined, then run a for loop and set one unknown card to 0, 1, 2 ... (players-1) and try to read the result from the hashmap. If it is not in the hashmap call the method itself and save the result in the map.
The recursion code should be something like this:
def recursion(players: Int, games: Int, unknownCards: Int, knownScore: Int): Int = {
unknownCards match {
case 0 if knownScore != games => 0
case 0 if knownScore == games => 1
case _ =>
map.get(players, unknownCards, knownScore) getOrElse {
var sum = 0
for (i <- 0 until players) sum += main(players, games, unknownCards - 1, knownScore + i)
sum %= 1000000007
map.put((players, unknownCards, knownScore), sum)
sum
}
}
}
Try this
import java.util.Scanner;
public class Solution {
final private static int size = 780;
private static long[][] possibleSplits = new long[size][size];
static {
for(int i=0; i < size; ++i)
possibleSplits[i][0] = 1;
for(int j=0; j< size; ++j)
possibleSplits[0][j] = j+1;
for(int i=1; i< size; ++i)
for(int j=1; j < size; ++j)
{
possibleSplits[i][j] = (possibleSplits[i-1][j] + possibleSplits[i][j-1]) % 1000000007;
}
}
public long possibleWays = 0;
public Solution(int n, String scores)
{
long totalScores = 0;
int numOfErasedScores = 0;
for(String str : scores.split(" "))
{
int s = Integer.parseInt(str);
if (s < 0)
++numOfErasedScores;
else
totalScores += s;
}
long totalErasedScores = ncr(n,2) - totalScores;
if(totalErasedScores == 0)
++possibleWays;
else if (totalErasedScores > 0)
partition(n-1, totalErasedScores, numOfErasedScores);
}
private void partition(int possibleMax, long total, int split)
{
if (split == 0)
return;
possibleWays = possibleSplits[(int)total-1][split-1];
if (total > possibleMax)
possibleWays -= split;
}
public static void main(String[] args)
{
Scanner in = new Scanner(System.in);
int numberOfTestCases = Integer.parseInt(in.nextLine().trim());
for(int i=0; i< numberOfTestCases; ++i)
{
String str = in.nextLine().trim();
int numberOfPlayers = Integer.parseInt(str);
String playerScores = in.nextLine().trim();
long result = new Solution(numberOfPlayers, playerScores).possibleWays;
System.out.println(result % 1000000007);
}
in.close();
}
public static long ncr(int n, int r)
{
long result = 1;
for(int i= Math.max(n-r, r)+1;i<=n;++i)
result*= i;
result/= fact(Math.min(n-r,r));
return result;
}
public static long fact(int n)
{
long result = 1;
for(int i =2; i<= n; ++i)
result *= i;
return result;
}
}

Resources