Facebook Interview Question
Software Engineer / DevelopersCountry: United States
Interview Type: Phone Interview
For second part in which similar digits remains in the end, we can continue like circular array.
I mean end part of array for similar digits can be replaced with digits in initial part of array.
Can you explain to me how you arrived at the conclusion: "will have no solution if a digit occurs more than n - (n/m)" ..
let's say , m = 2 , n = 6 , then according the above logic we can't have a number repeated more than 3 i.e. ( 6 - 6/2) = 3
counter example:
111122
112112
sorry i gave an approx for the limit the right limit is N- (N/(M +1))
the results comes from if you have N objects then the min number of separators required is N/(M+1)
Yes, max repeat characters should be N-(N/M+1) = (N)* (M / (M+1))
So if repeated characters are greater than N * M / (M+1), then there will be no solution.
Can someone explain this solution a bit more in detail? Where does this two pointers point to and what is the criteria to select which positions to swap?
That's a good idea.
To improve run-time complexity (at the expense of space complexity), we can create a stack which stores for each consecutive appearance of an element - a point (element,consecutive_appearance). For instance, if the input is 2,1,1,1,3,4,4,4,5 - the stack would look like: {(2,1),(1,3),(3,1),(4,3),(5,1)}. This can be done in linear time.
The way the stack was built we know that it does not have any two consecutive elements whose integer values are the same. This means that when we extract an element from the stack the only thing we need to do in order to find an integer which differs from it is just look at the head of the stack.
private static class Occurence<T> {
private T element;
private int count;
public Occurence(T element, int count){
this.element = element;
this.count = count;
}
public boolean isPositiveCount(){return count>0;}
public void increment(){count++;}
public void decrement(){count--;}
public void reduceCount(int k){count-=k;}
public void increaseCount(int k){count+=k;}
public T getElement(){return element;}
public int getCount(){return count;}
}
private static <T> Stack<Occurence<T>> buildCountStack(T[] arr){
if (arr==null){return null;}
Stack<Occurence<T>> stack = new Stack<Occurence<T>>();
for (int i=0;i<arr.length;i++){
if ((!stack.isEmpty()) && (stack.peek().getElement().equals(arr[i]))){
stack.peek().increment();
}
else {
stack.push(new Occurence<T>(arr[i],1));
}
}
return stack;
}
private static <T> Stack<Occurence<T>> splitOccurences(Stack<Occurence<T>> stack, int m){
if ((stack==null) || (stack.isEmpty()) || (m<1)){return stack;}
Stack<Occurence<T>> res = new Stack<Occurence<T>>();
Occurence<T> cur = stack.pop();
while (!stack.isEmpty()){
if (cur.getCount()>m){
res.push(new Occurence<T>(cur.getElement(),m));
cur.reduceCount(m);
res.push(new Occurence<T>(stack.peek().getElement(),1));
stack.peek().decrement();
if (!stack.peek().isPositiveCount()){
stack.pop();
if ((!stack.isEmpty()) && (stack.peek().getElement().equals(cur.getElement()))){
cur.increaseCount(stack.pop().getCount());
}
}
}
else {
res.push(cur);
cur = stack.pop();
}
}
res.push(cur);
return res;
}
public static <T> boolean removeConsecutives(T[] arr,int m){
if (m<1){return false;}
Stack<Occurence<T>> stack = splitOccurences(splitOccurences(buildCountStack(arr),m),m);
if ((stack==null) || (stack.isEmpty()) || (stack.peek().getCount()>m)){return false;}
int i=0;
while ((!stack.isEmpty()) && (i<arr.length)){
Occurence<T> cur = stack.pop();
for (int j=0;(j<cur.getCount()) && (i<arr.length);j++){arr[i++]=cur.getElement();}
}
return true;
}
Complexity: O(n) worst-case run-time complexity and O(n) space complexity.
I don't think I understand your approach very well. Wouldn't your algorithm fail for the case 4,1,1,1,4,1,1,1?
assuming M=2..
41141111 => 1st pass (L->R)
41111411 -> 11411411 => 2nd pass(R->L) so it dint fail
11411411 is the solution and yes the linear algorithm works.. you haven't understood the algorithm
case1: 14114111 -> 14114111-> 14111411-> 11411411
case2: 14111411 -> 14114111-> 14111411-> 11411411
Anonymous, the output of the linear algorithm for the two cases you suggested:
Input:14114111, m=2
Output: 11411411
Input: 14111411, m=2
Output: 11411411
In both cases the output is right.
The linear algorithm uses the same idea as kkr.ashish suggested only instead of iterating through the array and swapping elements, it just stores consecutive identical elements in the form of (element,count) in a stack according to the order of their appearance.
Then it pops elements from the stack and builds a new stack whose elements are yet again of the form (element,count) but the count is not greater than m for all the elements except maybe the element at the top (that's the equivalent of iterating right to left in kkr.ashish's algorithm).
After that we do the same once again with the new stack (the equivalent of iterating left to right in kkr.ashish's algorithm). If the element at the top of the resulting stack has a count greater than m then it's not possible to swap elements correctly. Otherwise, all that's left is to use the order and the count of the elements in the stack to construct the output array.
Run example (stack head is the rightmost element):
Input: {1,4,1,1,1,4,1,1} and m=2
1. Stack1 = {(1,1),(4,1),(1,3),(4,1),(1,2)}
2. Split elements in Stack1:
2.1. pop (1,2) from Stack1
2.2. The count in (1,2) is 2<=m so we push it to Stack2 (Stack2={(1,2)}
2.3. pop (4,1) from Stack1
2.4 The count in (4,1) is 1<=m so we push it to Stack2 (Stack2={(1,2),(4,1)})
2.5. pop (1,3) from Stack2
2.6. The count in (1,3) is 3>m so we need to split it, we push (1,2) to Stack2 (Stack2={(1,2),(4,1),(1,2)}. We update the count in (1,3) to (1,1) because we removed two elements from it. Then we need to find an element other than 1 to insert to Stack2 and with the way we built Stack1 that element is in its head - (4,1). Hence we push (4,1) to Stack2 (Stack2={(1,2),(4,1),(1,2),(4,1)}), we decrement the count of Stack1's head element (Stack1 = {(1,1),(4,0)}). Because the count in the head of Stack1 is 0 we pop this element. Because the head of Stack1 includes the same element (1) as the element we are currently iterating over ((1,1)) we pop it and increase (1,1)'s count by 1 (because the head element we popped is (1,1)).
2.7. Our current element is (1,2=1+1) and Stack1 is empty so we push it to Stack2.
3. Stack2 = {(1,2),(4,1),(1,2),(4,1),(1,2)}. You can see that the count of all elements in Stack2 is already lesser/equal than m=2 which means that the next step is not really necessary but in general the last element in step 2.7 was pushed to Stack2 without checking whether its count is less/equal than m so it might be greater than m.
4. Perform step 2 on Stack2 and store the result in Stack3 (Stack3={(1,2),(4,1),(1,2),(4,1),(1,2)}).
5. The head of Stack3 includes an element whose count is not greater than m which means that a solution is feasible.
6. Fill the output array from Stack3 the same way you created Stack1 in step 1. For Stack3={(1,2),(4,1),(1,2),(4,1),(1,2)}, the output array is {1,1,4,1,1,4,1,1} as desired.
Hopefully its clearer now.
Can you please explain output. Do we need to remove excess integers from output or we have to reposition them ??
As what 4 is doing in the end of output?
is output 112344514 correct for input 2,1,1,1,3,4,4,4,5 M = 2 ?
i am using hashtable of size 10 to store occurrence of digits in the number entered.
if any digit is occurring more than M times continuously, I am printing M digits at that time and printing remaining digits later at the end... How's that?
Can you please explain the question? Did you mean any group with size less than M should not contain same integers? Also, I think the group in this case would be formed from continuous sequence of integers?
for instance:
1,1,2 with M = 1 -> 1,2,1 -> 1,1 was a group of same integers with size bigger than M
2,1,1 with M = 1 -> 1,2,1
1,1,1,2,3,3,3,4 with M = 2 -> 1,1,2,1,3,3,4,3
the code works only for array of size 10 as i have statically defined an array of size 10
#include<stdio.h>
#include<conio.h>
int main()
{
int i,p,n=0,m=0,temp;
int a[10];
printf("enter 10 elements in array");
for(i=0;i<10;i++)
scanf("%d",&a[i]);
printf("enter m\n");
scanf("%d",&m);
n=a[0];
int c=1;
for(i=1;i<10;i++)
{
if(a[i]==a[i-1])
{
c++;
}
else
{
n=a[i];
c=1;
}
if(c==m+1)
{
if(i==9)
p=0;
else
p=i+1;
while(a[p]==a[i])
{
if(p==9)
p=0;
else
p++;
}
temp=a[p];
a[p]=a[i];
a[i]=temp;
n=a[i];
c=1;
}
}
for(i=0;i<10;i++)
printf("%d ",a[i]);
getch();
return 0;
}
Java Code. Complexity O(n). Done by using two array indexes.
public class TestOnly{
public static void main(String args[]){
int arr[] = {2,1,1,1,3,4,4,4,5};
int m = 2;
rearrange(arr,m);
System.out.println(Arrays.toString(arr));
}
public static void rearrange(int[] arr,int m){
int i=0;
int j=0,count=0;
while(i<arr.length-1){
count=1;
j = i + 1;
while( j<arr.length && arr[i] == arr[j]){
count++;
j++;
}
if(count > 2){
if(j>arr.length -1){
j = (j % arr.length);
}
int tmp = arr[i+m];
arr[i+m] = arr[j];
arr[j] = tmp;
i = i+m;
}
i++;
}
}
}
#include<stdio.h>
#include<conio.h>
void main()
{
int a[10],i,j,k,value,temp,count,M;
clrscr();
printf("\n\nEnter array:");
for(i=0;i<10;i++)
scanf("%d",&a[i]);
printf("\nEnter M") ;
scanf("%d",&M);
printf("\nYour array :");
for(i=0;i<10;i++)
printf(" %d",a[i]);
count=0;
for(i=0;i<10;i++)
{
count=0;
for(j=i;j<10;j++)
{
if(a[i]==a[j])
count++;
else
break;
if(count>M)
{
for(k=j;k<10;k++)
{
if(a[j]!=a[k])
{
value=a[k];
break;
}
}
temp=a[j];
a[j]=value;
a[k]=temp;
break;
}
}
}
printf("\nYour Output:");
for(i=0;i<10;i++)
printf(" %d",a[i]);
getch();
}
#include<stdio.h>
#include<conio.h>
void main()
{
int a[10],i,j,k,value,temp,count,M;
clrscr();
printf("\n\nEnter array:");
for(i=0;i<10;i++)
scanf("%d",&a[i]);
printf("\nEnter M") ;
scanf("%d",&M);
printf("\nYour array :");
for(i=0;i<10;i++)
printf(" %d",a[i]);
count=0;
for(i=0;i<10;i++)
{
count=0;
for(j=i;j<10;j++)
{
if(a[i]==a[j])
count++;
else
break;
if(count>M)
{
for(k=j;k<10;k++)
{
if(a[j]!=a[k])
{
value=a[k];
break;
}
}
temp=a[j];
a[j]=value;
a[k]=temp;
break;
}
}
}
printf("\nYour Output:");
for(i=0;i<10;i++)
printf(" %d",a[i]);
getch();
}
/*
c#
*/
static int[] GroupOfIntegers(int[] unOrdered, int m)
{
if(unOrdered == null)
throw new ArgumentNullException();
SortedDictionary<int, int> grouped = new SortedDictionary<int,int>();
foreach(int i in unOrdered)
{
if(grouped.Keys.Contains(i))
grouped[i]++;
else
grouped.Add(i, 1);
}
int[] ordered = new int[unOrdered.Count()];
int z = 0;
foreach(KeyValuePair<int, int> kvp in grouped)
{
for(int i = 0; (i <= m - 1) && (i <= kvp.Value -1); i++)
{
Console.Write("{0} ", kvp.Key);
ordered[z] = kvp.Key;
}
z++;
}
Console.ReadLine();
return ordered;
}
public static int[] process(int[] arr, int m) {
int current = 0, j = 0;
int count = 1;
int last = -1;
int i = arr.length - 1;
while (i > 0) {
if (arr[i] == last) {
count++;
if (count > m) {
current = i;
j = current - 1;
// find the next different element
while (j > 0 && arr[j] == last) {
j--;
}
// swap arr[j] <-> arr[current]
int temp = arr[j];
arr[j] = arr[current];
arr[current] = temp;
count = 1;
}
} else {
count = 1;
}
last = arr[i];
i--;
}
return arr;
}
import java.util.Arrays;
public class Unordered_Array {
public static int[] swap (int a [] , int k, int j)
{
int temp;
temp = a[k];
a[k] = a[j];
a[j] = temp;
return a;
}
public static void main(String[] args)
{
int [] a = new int []{2,1,1,1,3,4,4,4,5};
int i=0,j=-1,k=0,count=1,first;
int M=2;
while (j < a.length-1)
{
first = a[i];
j = j+1;
if(first == a[j])
{
count ++;
if (count > M)
{
k = j+1;
while (first == a[k])
{
k++;
if (k == a.length)
{
break;
}
}
if (k == a.length)
{
System.out.println("Not Applicable");
break;
}
else
{
a = swap(a,k,j);
i = j+1;
j=i;
count =1;
}
}
}
else
i=j;
}
System.out.println(Arrays.toString(a));
}
}
import java.util.Arrays;
public class Unordered_Array {
public static int[] swap (int a [] , int k, int j)
{
int temp;
temp = a[k];
a[k] = a[j];
a[j] = temp;
return a;
}
public static void main(String[] args)
{
int [] a = new int []{2,1,1,1,3,4,4,4,5};
int i=0,j=-1,k=0,count=1,first;
int M=2;
while (j < a.length-1)
{
first = a[i];
j = j+1;
if(first == a[j])
{
count ++;
if (count > M)
{
k = j+1;
while (first == a[k])
{
k++;
if (k == a.length)
{
break;
}
}
if (k == a.length)
{
System.out.println("Not Applicable");
break;
}
else
{
a = swap(a,k,j);
i = j+1;
j=i;
count =1;
}
}
}
else
i=j;
}
System.out.println(Arrays.toString(a));
}
}
def rearange(list: List[Int], m: Int): List[Int] = {
import Math._
def fill(n: Int, i: Int) =
List.tabulate(n)(_ => i)
def findFreq(l: List[(Int, Int)]) =
if(l.length < 2) (l.head, Nil)
else l.tail.foldLeft((l.head, List.empty[(Int, Int)])) {
case ((a @ (_, c1), lst), b @ (_, c2)) => if(c1 > c2) (a, b :: lst) else (b, a :: lst)
}
def H(e: (Int, Int), l: List[(Int, Int)]) =
min(m, (l.map { case (_, c) => c }.sum + 1) / ((e._2 + m - 1) / m))
def rearange0(f: (Int, Int), lst: List[(Int, Int)], dx: Int): List[Int] = {
if(dx == 0) ???
(f, lst) match {
case ((_, c), l @ (_ :: _)) if c == 0 =>
val (e, t) = findFreq(l)
rearange0(e, t, H(e, t))
case ((k1, c1), l @ (_ :: _)) =>
val ((k2, c2), t) = findFreq(l)
val (s1, s2) = (min(c1, m), min(c2, dx))
val tail = (if(c2 - s2 > 0) (k2, c2 - s2) :: t else t)
fill(s1, k1) ::: fill(s2, k2) ::: rearange0((k1, c1 - s1), tail, dx)
case ((k, c), Nil) =>
fill(c, k)
}
}
val base = list
.groupBy { x => x }
.mapValues { _.length }
.toList
if(list.length == 0) Nil
else if(base.length == 1) {
if(list.length > m) Nil
else list
}
else {
val (e, t) = findFreq(base)
rearange0(e, t, H(e, t))
}
}
//keep the running count of only the current repeating integer
void modify(int arr[],int n,int M)
{
int i,count = 0;
//count holds count of repeating integer
for(i = 0; i < n-1; i++)
{
if(count == 0 || count <= M) //no character in continuation or allowed sequence
{
if(count == 0)
count = 1; //at least one occurence
while(i != n-1 && arr[i] == arr[i+1])
{
count++;
i++;
}
//now arr[i] != arr[i+1] or i = n-1
if(count > M)
{
if(i == n-1) //all characters repeating can't do a thing
break;
//else arr[i] != arr[i+1]
swap(arr+i+1,arr+i-count+M+1);
count -= M;
}
else //repetition is less than M,stay at original location
count = 0; //since count < M and arr[i] != arr[i+1]
}
else
{
//count > M
if(i != n-1 && arr[i] == arr[i+1])
{
count++;
i++;
}
//count > M definitely
if(i == n-1)
break;
swap(arr+i+1,arr+i-count+M+1);
count -= M;
}
}
}
sorry there are some mistakes in the code like in comments i have written characters and major mistake is in the else part i wrote if instead of while . I am giving the correct and checked code with time complexity O(n) ,check it out:---
void modify(int arr[],int n,int M)
{
int i,count = 0;
//count holds count of repeating integer
for(i = 0; i < n; i++)
{
if(count <= M)
{
if(count == 0)
count = 1; //new integer
while(i != n-1 && arr[i] == arr[i+1])
{
count++;
i++;
}
//now arr[i] != arr[i+1] or i = n-1
if(count > M)
{
if(i == n-1) //reached the end
break;
//else arr[i] != arr[i+1]
swap(arr+i+1,arr+i-count+M+1); //take M integers of this sequence
count -= M; //reduce count by M
}
else
count = 0; //count <= M and arr[i] != arr[i+1] so set count for next integer
}
else
{
//count > M
while(i != n-1 && arr[i] == arr[i+1])
{
count++;
i++;
}
if(i == n-1)
break;
swap(arr+i+1,arr+i-count+M+1); //take M integers of this sequence
count -= M; //reduce count by M
}
}
}
I found an O(n log(n)) solution.
I first find the number of occurrences of each object.
Then, break each number into batches of "M" repetitions, i.e., one Run.
Example:
sequence: 1, 1, 1, 1, 4, 4, 1
M = 2
Runs: (1, 1), (1, 1), (1) for type = 1
(4, 4) for type = 4
An object "Type" is defined as a set of Runs of same type. Type1 > Type2 if Type1 has more runs. This way, I can sort all Types descending. This is of course O(nlog(n)).
Lets assume "1" is the type with largest number of runs. Now if the total number of "other" runs is equal or greater than the number of runs of "1", we can proceed to making a proper output ("MakeSequence()" routine). Otherwise, I will break the runs into smaller runs until that happens. If not, then there is no solution. This step is linear in the number of Runs() < number of elements.
To make the sequence we do this:
a) Take out head of line in queue and remove one run add to sequence. If the Type is empty now, throw it away. If not, keep it somewhere but don't put in queue.
b) Take out another type. Add to sequence. If non-empty, keep it somewhere.
c) Now if there is a type outside, put it back into queue.
e) go back to a) until queue is empty.
Example (above):
Type1 = [(11), (11), (1)]
Type2= [(4,4)]
since Type1.nRuns() == 3 > Type2.nRuns() + 1, we will break Type2.
Type2=[(4),(4)].
Now we go to make sequence:
seq = "";
a)-> seq = "11", Type1 = [(1,1),(1)];
b)->seq="4",Type2=[(4)],
c) Type1 goes back into queue.
a)-> seq="11411"
b)->seq="114114";
c)->Type1 goes back in
a)->seq="1141141"
done!
here is the code:
public class SequenceSeparation {
public static int M = 2;
public static class Run {
String value;
int length;
public int getLength() {
return length;
}
public Run(String value) {
this.value = value;
this.length = 1;
}
public void add() {
length++;
}
public LinkedList<Run> breakRun(int n) {
LinkedList<Run> runs = new LinkedList<>();
while (n != 0 && length != 1) {
Run r = new Run(value);
runs.add(r);
n--;
length--;
}
runs.add(this);
return runs;
}
@Override
public String toString() {
String s = "";
for (int i = 0; i < length; i++)
s = s + value;
return s;
}
}
public static class Type implements Comparable<Type> {
String value;
int buffer = 0;
Run current_run = null;
LinkedList<Run> runs;
public Type(String value) {
this.value = value;
runs = new LinkedList<>();
current_run = new Run(value);
runs.add(current_run);
buffer = 1;
}
public Run nextRun() {
if (runs.isEmpty())
return null;
else
return runs.pollFirst();
}
public void add() {
if (buffer == 0) {
current_run = new Run(value);
runs.add(current_run);
buffer = 1;
}
else {
current_run.add();
}
if (current_run.length == M)
buffer = 0;
}
public String getValue() {
return value;
}
public Integer nRuns() {
return runs.size();
}
@Override
public int compareTo(Type o) {
return -nRuns().compareTo(o.nRuns());
}
public int increaseRuns(int n) {
Run first_run = null;
while (true) {
Run r = runs.getFirst();
if (first_run == null)
first_run = r;
else
if (first_run == r)
return n;
int c = runs.size();
while (r.getLength() == 1) {
runs.removeFirst();
runs.addLast(r);
r = runs.getFirst();
c--;
if (c == 0)
return n;
}
LinkedList<Run> new_runs = r.breakRun(n + 1);
runs.removeFirst();
int ii = new_runs.size();
for (int i = 0; i < ii; i++) {
Run rr = new_runs.pollFirst();
runs.addLast(rr);
}
n -= (ii - 1);
if (n == 0)
return 0;
}
}
}
public SequenceSeparation(String sequence, int M) {
SequenceSeparation.M = M;
String[] types = sequence.split(",");
HashMap<String, Type> repetitions = new HashMap<>();
// Round 1: count
Type max_type = null;
int ng = 0;
for (String t : types) {
if (repetitions.containsKey(t))
repetitions.get(t).add();
else
repetitions.put(t, new Type(t));
if (repetitions.get(t).nRuns() > ng) {
ng = repetitions.get(t).nRuns();
max_type = repetitions.get(t);
}
}
int n_total_other = 0;
for (String t : repetitions.keySet()) {
if (t.compareTo(max_type.getValue()) != 0)
n_total_other += repetitions.get(t).nRuns();
}
if (n_total_other + 1 < max_type.nRuns()) {
int diff = max_type.nRuns() - n_total_other - 1;
for (String t : repetitions.keySet()) {
if (t.compareTo(max_type.getValue()) != 0) {
Type type = repetitions.get(t);
diff = type.increaseRuns(diff);
}
}
if (diff > 0) {
System.out.println("Could not resolve.");
return;
}
}
MakeSequence(repetitions);
}
private void MakeSequence(HashMap<String, Type> repetitions) {
// A sorted-queue : MaxHeap (note the comparedTo defition for Type)
PriorityQueue<Type> queue = new PriorityQueue<>(repetitions.values());
Type type1 = null, type2 = null;
String seq = "";
while (queue.isEmpty() == false) {
type2 = type1;
Type next = queue.poll();
seq += next.nextRun().toString();
if (next.nRuns() > 0)
type1 = next;
else
type1 = null;
if (type2 != null)
queue.add(type2);
}
System.out.println("Solution:");
System.out.print(seq);
}
}
O(nlog(n)) solution
import java.util.Arrays;
import java.util.Scanner;
public class No_size_bigger {
static void Print_no_Bigger(int [] array,int M){
Arrays.sort(array);
int Number_of_occurences=1;
int current_Number=array[0];
System.out.print(current_Number+" ");
for(int i=1;i<array.length;i++){
if(array[i]==current_Number){
Number_of_occurences++;
if(Number_of_occurences<=M){
System.out.print(array[i]+" ");
}
}else{
current_Number=array[i];
Number_of_occurences=1;
System.out.print(array[i]+" ");
}
}
}
public static void main(String [] args){
Scanner input=new Scanner(System.in);
int [] array={2,1,1,1,3,4,4,4,5,5,5,5,7,7,8,8,8,9,9,9,9};
Print_no_Bigger(array,3);
}
}
Hello, thank you for sharing your solution. Your solution is similar to the solution to "Remove Duplicates in Sorted Array II" in Leetcode. However, I think this problem is different because it requires you to relocate the numbers so that no consecutive same numbers of size larger than M is allowed, rather than just ignoring numbers as you did in your solution.
Python:
def nobigger(l, m, last=None, count=0):
if len(l) >= m:
if l[0] == last and count < m-1:
return [l[0]] + nobigger(l[1:], m, last, count+1)
elif l[0] == last:
return nobigger(l[1:], m, last, count+1)
else:
return [l[0]] + nobigger(l[1:], m, l[0], 0)
else:
return l
print nobigger([2,1,1,1,3,4,4,4,5], 2)
Scan the numbers and store it in a Hashmap.
Hashmap : (number,count)
if the size of the group is m.
Iterate through the HashMap, picking up m different elements and reducing the count.
perform the above operation n/m times
Thus the overall complexity = O(n) {for updating hashMap}+O(n){for iterating through HashMap}
=O(n)
public class Solution{
public void trans(int [] A ,int M){
for(int i = 0 ; i < A.length - 1; ){
int j = i + 1, count = 1;
while(j < A.length){
if(A[j] == A[j - 1]) {
count ++;
j ++;
}
else {
if(count <= M) { i = j; break;}
int tmp = A[i + M ];
A[i + M ] = A[j];
A[j] = tmp;
count -= M - 1;
j++;
i = i + M + 1;
}
}
if(j == A.length ) break;
}
}
public void solve(int [] A , int M){
trans(A, M);
reverse(A);
trans(A , M);
}
public void reverse(int [] A){
for(int i = 0 ; i < A.length /2 ; i++) {
int tmp = A[i];
A[i] = A[A.length - 1 - i];
A[A.length - 1 -i] = tmp;
}
}
}
public class Solution{
public void trans(int [] A ,int M){
for(int i = 0 ; i < A.length - 1; ){
int j = i + 1, count = 1;
while(j < A.length){
if(A[j] == A[j - 1]) {
count ++;
j ++;
}
else {
if(count <= M) { i = j; break;}
int tmp = A[i + M ];
A[i + M ] = A[j];
A[j] = tmp;
count -= M - 1;
j++;
i = i + M + 1;
}
}
if(j == A.length ) break;
}
}
public void solve(int [] A , int M){
trans(A, M);
reverse(A);
trans(A , M);
}
public void reverse(int [] A){
for(int i = 0 ; i < A.length /2 ; i++) {
int tmp = A[i];
A[i] = A[A.length - 1 - i];
A[A.length - 1 -i] = tmp;
}
}
}
O(n) Solution.
Go through the list twice.
The first pass is to try to find right hand side number to slice the left consecutive sequence. The second pass is the other way around.
Solution assumes an answer exists.
Proof:
Assume an answer exists.
The first pass could only possibly leave the right most consecutive to be invalid. The second pass would leave the first to be invalid. Since in the first pass we already make sure the first(left most) consecutive sequence to be valid , the only reason for the left most to be invalid is it has the same value as the right most sequence. Consider the example (1,1,2,2,3,3,1,1,1,1,1,1........) the 1 would propagate to the left. If the left most sequence becomes invalid, we can infer no answer exists, where contradiction occurs.
public class Solution{
public void trans(int [] A ,int M){
for(int i = 0 ; i < A.length - 1; ){
int j = i + 1, count = 1;
while(j < A.length){
if(A[j] == A[j - 1]) count++;
else {
if(count <= M) { i = j; break;}
int tmp = A[i + M ];
A[i + M ] = A[j];
A[j] = tmp;
count -= M ;
i = i + M + 1;
}
j++;
}
if(j == A.length ) break;
}
}
public void solve(int [] A , int M){
trans(A, M);
reverse(A);
trans(A , M);
}
public void reverse(int [] A){
for(int i = 0 ; i < A.length /2 ; i++) {
int tmp = A[i];
A[i] = A[A.length - 1 - i];
A[A.length - 1 -i] = tmp;
}
}
}
func(arr, m);
int i = 0;
int j = arr.length -1;
while(i < j)
{
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
++i;
--j;
}
func(arr, m);
func(int[] arr, int m)
{
if(m < 1 || arr == null) throw new IllegalArgumentException();
int index = 0;
int upto = arr.length - m;
while(index < upto)
{
int firstVal = arr[index];
int count = 1;
for(int i=index+1; i<=(index + m); ++i)
{
if(firstVal == arr[i])
{
count++;
}else
{
break;
}
}
if(count > m)
{
int newIndex = index + m + 1;
while(newIndex < arr.length)
{
if(firstVal != arr[newIndex])
{
int temp = arr[index + m];
arr[index + m] = arr[newIndex];
arr[newIndex] = temp;
index = index + m;
break;
}
++newIndex;
}
}
++index;
}
}
Below is an inplace code:
#include<iostream>
#include<conio.h>
using namespace std;
void remDup(int a[],int n,int m){
int i=0,j=0,k=0;
while(i<n){
k=0;
if(i+1<n&&a[i]!=a[i+1]) a[j++]=a[i++]; //if it is not duplicated at all
while(i<n-1&&a[i]==a[i+1]&&k<m){ //copy all duplicates till k<m
a[j++]=a[i++];
k++;
}
if(k<m) a[j++]=a[i]; //copy the last element if k<m
while(i+1<n&&a[i]==a[i+1]) i++; //skip all the othr same elements
i++;
}
if(k<m&&a[i-1]!=a[i-2]) a[j++]=a[i-1]; //last element is copied if it can be taken
for(int i=0;i<j;i++) cout<<a[i]<<" ";
}
int main(){
int a[]={2,1,1,1,3,4,4,4,4,5,5,5,6,6,7,8};
int n=16,m=2;
remDup(a,n,m);
getch();
}
public static int[] arrayFormat(int[] a, int m) {
int count = 0;
int i = 0;
int len = a.length;
while (i<len-1) {
if(a[i] == a[i+1]) {
count++;
if(count >= m) {
a = adjustPos(a, i);
}
} else {
count = 0;
}
len = a.length;
i++;
}
return a;
}
public static int[] adjustPos(int [] a, int pos) {
int [] ad = new int[a.length -1];
for (int i = 0; i < pos; i++) {
ad[i] = a[i];
}
for (int i = pos; i < a.length-1; i++) {
ad[i] = a[i+1];
}
return ad;
}
This is Java solution with running complexity of O(2n) = O(n)
and space complexity of O(2n) = O(n)
I might lower to space complexity to only one extra array but the solution will be less clean.
public static int[] removeKDuplicates(int[] list, int k)
{
// i use ArrayList because the final size is unknown
ArrayList<Integer> newList = new ArrayList<Integer>();
int counter = 0;
// since the integers are positive -1 must be unique
int prev = -1;
for (int current : list)
{ if ( prev == current )
{
++counter;
if ( counter >= k)
{
continue;
}
}else
{
counter = 0;
prev = current;
}
newList.add(current);
}
// copy the Array to int[]
int[] returnedList = new int[newList.size()];
for (int i = 0; i < returnedList.length ; i++)
{
returnedList[i] = newList.get(i);
}
return returnedList;
}
My Algorithm:
1) Keep pointer to start and end of array.
2) keep on counting number from start if ( cur_num == prev_num) count++; and do start++.
3) if (count > k), then swap(cur_elem, last_elem) and decrement last pointer (last--); but don't do start++ at this step.
4) Now check the (2) condition for swapped element and (cur_elem != prev_elem) then, do start++, and last = n-1;
5) keep on doing same thing until (start == last)
In Java:
private void arrangeTwoEqualsMax() {
int[] array = new int[]{2,1,1,1,3,4,4,4,5};
for (int i = 0; i < array.length - 3; i++) {
if (array[i] == array[i+1] && array[i] == array[i+2]) {
findDifferent(array, i + 2);
}
}
System.out.println("Arranged array: " + Arrays.toString(array));
}
private void findDifferent(int[] array, int index) {
if (array[index] == array[index + 1]) {
findDifferent(array, index + 1);
} else {
int temp = array[index + 1];
array[index + 1] = array[index];
array[index] = temp;
}
}
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.PriorityQueue;
public class GroupElementInSizeM{
class Node{
int key;
int freq;
public Node(int key, int freq) {
this.key = key;
this.freq = freq;
}
}
public int[] groupinSizeM(int[] intArray, int M) {
if (intArray == null || intArray.length == 0) {
return intArray;
}
Comparator<Node> nodeComp = new Comparator<Node>() {
public int compare(Node n1, Node n2) {
return n2.freq - n1.freq;
}
};
PriorityQueue<Node> maxHeap = new PriorityQueue<>(nodeComp);
Map<Integer, Integer> freqMap = new HashMap<>();
for (int i : intArray) {
if (freqMap.containsKey(i)) {
freqMap.put(i, freqMap.get(i) + 1);
} else {
freqMap.put(i, 1);
}
}
for (int key : freqMap.keySet()) {
maxHeap.add(new Node(key, freqMap.get(key)));
}
int pointer = 0;
while (!maxHeap.isEmpty()) {
Node v = maxHeap.poll();
int maxPossible = (pointer != 0 && v.key == intArray[pointer - 1]) ? M - 1 : M;
for (int i = 0; i < Math.min(maxPossible, v.freq); i++) {
intArray[pointer++] = v.key;
}
v.freq -= Math.min(maxPossible, v.freq);
if (v.freq > 0) {
if (maxHeap.isEmpty()) {
return null;
}
Node next = maxHeap.poll();
intArray[pointer++] = next.key;
next.freq--;
if (next.freq > 0) {
maxHeap.add(next);
}
maxHeap.add(v);
}
}
return intArray;
}
}
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.PriorityQueue;
public class GroupElementInSizeM{
class Node{
int key;
int freq;
public Node(int key, int freq) {
this.key = key;
this.freq = freq;
}
}
public int[] groupinSizeM(int[] intArray, int M) {
if (intArray == null || intArray.length == 0) {
return intArray;
}
Comparator<Node> nodeComp = new Comparator<Node>() {
public int compare(Node n1, Node n2) {
return n2.freq - n1.freq;
}
};
PriorityQueue<Node> maxHeap = new PriorityQueue<>(nodeComp);
Map<Integer, Integer> freqMap = new HashMap<>();
for (int i : intArray) {
if (freqMap.containsKey(i)) {
freqMap.put(i, freqMap.get(i) + 1);
} else {
freqMap.put(i, 1);
}
}
for (int key : freqMap.keySet()) {
maxHeap.add(new Node(key, freqMap.get(key)));
}
int pointer = 0;
while (!maxHeap.isEmpty()) {
Node v = maxHeap.poll();
int maxPossible = (pointer != 0 && v.key == intArray[pointer - 1]) ? M - 1 : M;
for (int i = 0; i < Math.min(maxPossible, v.freq); i++) {
intArray[pointer++] = v.key;
}
v.freq -= Math.min(maxPossible, v.freq);
if (v.freq > 0) {
if (maxHeap.isEmpty()) {
return null;
}
Node next = maxHeap.poll();
intArray[pointer++] = next.key;
next.freq--;
if (next.freq > 0) {
maxHeap.add(next);
}
maxHeap.add(v);
}
}
return intArray;
}
}
my implementation based on more rated post
public void ArrengeByWindow(int[] a, int m)
{
var set = new HashSet<int>();
for (int i=0; i < a.Length; i++)
{
if (set.Contains(a[i]))
{
int j = a.Length - 1;
while (j > i)
{
if (set.Contains(a[j]))
j--;
else
{
int tmp = a[i];
a[i] = a[j];
a[j] = tmp;
break;
}
}
if (i == j)
throw new Exception();
}
set.Add(a[i]);
if (set.Count == m)
set.Clear();
}
}
we can take two pointers and store the occurance count and move left to right and swapping at any occurance of more than M with the next difference number.. this will leave same digits in the end .. so you will need to move from right to left and refill them.. will have no solution if a digit occurs more than N - (N/M) times in the pattern
- kkr.ashish January 22, 2014