I have an exercise in which I have to sort an array in the following way:
the numbers that divide 4 with no remainder will be the first in the array (e.g 4,8,12,16).
the numbers that divide 4 with remainder of 1 will be the second in the array (1,5,9).
the numbers that divide 4 with remainder of 2 will be the third in the array (2,6,10).
the numbers that divide 4 with remainder of 3 will be last in the array.
For example, the following array:
int []a={1,7,3,2,4,1,8,14}
will be:
4 8 1 1 2 14 3 7
the order within the groups does not matter.
I have found a solution which works on O(n) time complexity and O(1) space complexity.
However, it is ugly and moves on the array 3 times. I would want a more elegant solution.
This is my code:
int ptr=a.length-1; int temp=0, i=0;
while (i<ptr){
//move 3 remained to the end
if (a[i] % 4==3){
temp=a[ptr];
a[ptr]=a[i];
a[i]=temp;
ptr--;
}
else
i++;
}
i=0;
while (i<ptr){
if (a[i]%4==2)
{
temp=a[ptr];
a[ptr]=a[i];
a[i]=temp;
ptr--;
}
else
i++;
}
i=0;
while (i<ptr){
if (a[i]%4==1)
{
temp=a[ptr];
a[ptr]=a[i];
a[i]=temp;
ptr--;
}
else
i++;
}
Important to know:
I don't want time complexity worse than O(n), and space complexity worse than O(1).
Since O(3 * N) is O(N), you only need to loop through the array three times:
Move the elements e % 4 == 0 to the front, swapping elements along the way;
Move the elements e % 4 == 1 to the front, swapping elements along the way;
Move the elements e % 4 == 2 to the front, swapping elements along the way;
The elements that e % 4 == 3 will be at the end after this.
Example:
public static void main(String args[]) {
int[] a = { 1, 7, 3, 2, 4, 1, 8, 14 , 9};
int current = 0;
for (int i = 0; i < 3; i++) {
for (int j = current; j < a.length; j++) {
if (a[j] % 4 == i) {
int b = a[j];
a[j] = a[current];
a[current] = b;
current++;
}
}
}
System.out.println(Arrays.toString(a));
}
Just use a comparator and make use for the very efficient internal sort algorithm.
Arrays.sort(a, new Comparator() {
public int compare(int a, int b) {
if(a%4 == b%4) {
if(a < b) return -1;
if(a > b) return 1;
return 0;
} else {
if(a%4 < b%4) return -1;
if(a%4 > b%4) return 1;
return 0;
}
}
});
You can use up more memory. This is not correct, but I will still put it.
int modulusLength = 4;
List<Integer> array[] = new List<Integer>[modulusLength];
for(int i = 0; i < modulusLength; i++)
array[i] = new ArrayList<Integer>;
for(int i = 0 ; i < a.length; i++)
array[a[i]%modulusLength].put(a[i]);
int counter = 0;
for(int i = 0 ; i < array.length; i++)
for(int j = 0; j < array[i].size; j++)
{
a[counter] = array[i].get(j);
counter++;
}
Horrible and scary, but was fun to write. And it works :)
Related
I've earlier used nested approach which is giving me TLE.
-we can not use nested approach for this.
- time limit is 1 sec and 5000kb memory. Here is my nested approach
for (int i = 0; i < n; i++) {
if (arr[i] > 0) {
int count = 1;
for (int j = i + 1; j < n; j++)
if (arr[i] == arr[j])
count += 1;
if (count == k)
res = Math.min(res, arr[i]);
}
}
You can try using a dictionary that keeps track of the numbers as keys, and the number of times it appears as the value. This way you will only have to go through the array once.
Then, at the end you check which keys have a value of K, and choose the smallest of those.
Firstly you should get the max element and make count array of length max+1 elements i.e how much time each elements occurring eg:-
arr=[2,5,1,2,3,6,3] and k=2.
Now count each element, n is length of array, c is array counting element
int c[]=new int[max+1];
for(int i=0;i<=max; i++)
{
c[a[i]]+=1;
}
Arrays.sort(a);
//1 2 2 3 3 5 6
for(int i=0;i<n;i++)
{
if(c[a[i]]==k)
{
System.out.print(a[i]);
break;
}
}
This will give you desired output with time complexity O(nLogn)
How about just sorting the array and then walking through it to return the first value that occurs k times?
// return the smallest value that occurs k times, or null if none found
static Integer smallestK(int[] a, int k)
{
Arrays.sort(a);
for(int i=1, j=0; i<=a.length; i++)
{
if(i == a.length || a[i] != a[j])
{
if(i - j == k)
return a[j];
j = i;
}
}
return null;
}
Test:
int[] a = {6, 5, 3, 1, 4, 2, 5, 2, 2};
System.out.println(Arrays.toString(a));
for(int k=1; k<=4; k++)
{
Integer val = smallestK(a.clone(), k);
if(val != null)
System.out.format("k:%d, Result: %d%n", k, val);
else
System.out.format("k:%d, Not Found", k);
}
Output:
[6, 5, 3, 1, 4, 2, 5, 2, 2]
k:1, Result: 1
k:2, Result: 5
k:3, Result: 2
k:4, Not Found
You can try below approach as well. it has O(nlogn) complexity.
int[] arr1 = {10,2,15,20,25,4,25};//array
int k = 2;//minimum occurences
Arrays.sort(arr1);
HashMap<Integer,Integer> value = new HashMap<Integer, Integer>();
for(int i:arr1) {
value.put(i, value.getOrDefault(i, 0)+1);
}
for(int i:arr1) {
if(value.get(i)==k) {
System.out.println(i);
break;
}
}
I can't solve the problem , where I need output from array A like {1,2,3,4,-1,-2,-3,-4}
from random numbers in array, then write it to another array B. So far my experimental code doesn't work as I'd
public static void main(String[] args) {
int a[] = {5,4,3,2,1,-3,-2,-30};
int length = a.length - 1;
for (int i = 0 ; i < length ; i++) {
for (int j = 0 ; j < length-i ; j++) {
if (a[j] < a[j+1]) {
int swap = a[j];
a[j] = a[j+1];
a[j+1] = swap;
}
}
}
for (int x : a) {
System.out.print(x+" ");
}
}
Output is 5 4 3 2 1 -2 -3 -30 , but I need 1,2,3,4,5,-2,-3,-30
Update:
public static void main(String[] args) {
int a[] = {5,4,3,2,1,-3,-2,-30,-1,-15,8};
int length = a.length - 1;
for (int i = 0 ; i < length ; i++) {
for (int j = 0 ; j < length-i ; j++) {
if (a[j] < a[j+1]) {
int swap = a[j];
a[j] = a[j+1];
a[j+1] = swap;
} else {
if (a[j] > a[j+1] && a[j+1] > 0) {
int swap = a[j];
a[j] = a[j+1];
a[j+1] = swap;
}
}
}
}
for (int x : a) {
System.out.print(x+" ");
}
}
I got closer to my target but 8 1 2 3 4 5 -1 -2 -3 -15 -30 , that number 8 ruins it all
Add an if-else to differentiate the positive and negative case.
if (a[j] < 0) {
if (a[j] < a[j+1]) {
int swap = a[j];
a[j] = a[j+1];
a[j+1] = swap;
}
} else {
if (a[j] > a[j+1] && a[j+1] > 0) {
int swap = a[j];
a[j] = a[j+1];
a[j+1] = swap;
}
}
If I understand you correctly you want to sort after two things. Positive numbers from low to high and negative numbers from high to low.
You could first sort from high to low and in a second run over the array skip all positives and then sort from high to low.
Does this help?
I could write some code, but I believe that's something you want to learn right now :)
Algo:
Traverse the Array and Store positives in one and Negatives in another. O(i)
Sort the positives array in ascending order. O(mLog(m))
Sort the negatives indescending order. O(nLog(n))
Create a final array of the size of the input.
Add all the positive array sorted values. Then add the negative array sorted values. O(i)
Total : O(i) + O(mLog(m)) + O(nLog(n)) + O(i) = O(mLog(m)) if m > n
I have used library functions here. But if you want you can the write the functions using the same idea.
public class PostivieAsendingNegativeDesending implements Comparator<Integer> {
public static void main(String args[]) {
int fullList[] = {5, 4, 3, 2, 1, -3, -2, -30};
ArrayList<Integer> subList = new ArrayList<>();
ArrayList<Integer> subList2 = new ArrayList<>();
for (int i = 0; i < fullList.length; i++) {
if (fullList[i] < 0) {
subList2.add((fullList[i]));
} else {
subList.add(fullList[i]);
}
}
Collections.sort(subList);
Collections.sort(subList2, new PostivieAsendingNegativeDesending());
subList.addAll(subList2);
for (int i = 0; i < subList.size(); i++) {
System.out.print(subList.get(i) + " ");
}
System.out.println("");
}
#Override
public int compare(Integer n1, Integer n2) {
return n2 - n1;
}
}
This will do the trick which uses only basic loops
public static void main(String[] args) {
int a[] = { 5, 4, 3, 2, 1, -3, -2, -30 };
int length = a.length - 1;
int pos = 0, neg = 0;
// find total count of positive and negative numbers
for (int i = 0; i <= length; i++) {
if (a[i] < 0)
neg++;
else
pos++;
}
// initialize the arrays based on 'pos' and 'neg'
int posArr[] = new int[pos];
int negArr[] = new int[neg];
// store pos and neg values in the arrays
int countPos = 0, countNeg = 0;
for (int i = 0; i <= length; i++) {
if (a[i] < 0) {
negArr[countNeg] = a[i];
countNeg++;
} else {
posArr[countPos] = a[i];
countPos++;
}
}
// sort positive numbers
for (int i = 0; i < posArr.length - 1; i++) {
for (int j = 0; j < posArr.length - 1 - i; j++) {
if (posArr[j] > posArr[j + 1]) {
int swap = posArr[j];
posArr[j] = posArr[j + 1];
posArr[j + 1] = swap;
}
}
}
// sort negative numbers
for (int i = 0; i < negArr.length - 1; i++) {
for (int j = 0; j < negArr.length - 1 - i; j++) {
if (negArr[j] < negArr[j + 1]) {
int swap = negArr[j];
negArr[j] = negArr[j + 1];
negArr[j + 1] = swap;
}
}
}
// 1. print out posArr[] and then negArr[]
// or
// 2. merge them into another array and print
}
Logic is explained below :
Find total count of positive and negative numbers.
Create and store the positive and negative values in the respective arrays.
Sort positive array in ascending order.
Sort negative array in descending order.
Print out positive array followed by the negative array OR merge them into another and print.
I suggest another approach. You should try to formulate the rules to which the exact comparison must adhere.
Your requirement seem to have the following rules:
Positive numbers always come before negative numbers.
Positive numbers are ordered in ascending order.
Negative numbers are ordered in descending order. Yes, I said descending. Since higher numbers come before lower numbers, i.e. −2 is greater than −7.
Warning: you are using a nested for loop, which means that the process time will grow exponentially if the array becomes larger. The good news is: you don't need to nest a for loop into another for loop. I suggest writing a Comparator instead:
// The contract of Comparator's only method 'compare(i, j)' is that you
// return a negative value if i < j, a positive (nonzero) value if i > j and
// 0 if they are equal.
final Comparator<Integer> c = (i, j) -> { // I'm using a lambda expression,
// see footnote
// If i is positive and j is negative, then i must come first
if (i >= 0 && j < 0) {
return -1;
}
// If i is negative and j is positive, then j must come first
else if (i < 0 && j >= 0) {
return 1;
}
// Else, we can just subtract i from j or j from i, depending of whether
// i is negative or positive
else {
return (i < 0 ? j - i : i - j);
}
}
Your code could look like this:
int[] a = { 5, 4, 3, 2, 1, -3, -2, -30 };
int[] yourSortedIntArray = Arrays.stream(a)
.boxed()
.sorted(c) // Your Comparator, could also added inline, like
// .sorted((i, j) -> { ... })
.mapToInt(i -> i)
.toArray();
Lambda expressions are a new concept from Java 8. The Java Tutorials provide some valuable information.
I'm developing a game in Android Studio using Java, and I have some troubles with the method that does the counting of the score. Basically in the game I have an array of dices that have values from 1 to 6. Among these values I need to find how many times a special value appears.
Right now I have a method that makes it work fine for finding all single values (like all dices that have the value 5), and also if two dices add up to the special value (like 2 + 3, or 1 + 4). But it doesn't find the special value when there's more than two dices adding up to the number (like 1 + 1 + 3)
Example: If I have the dices with values [1, 2, 2, 2, 3, 5]
The result should be three "numberOfPairs" (1+2+2, 2+3, 5) and therefore the method should return 15, but for me it only returns 10.
I would really appreciate some ideas how to change this method to work better.
Here's the method I've been working on now:
public static int evaluatePoints(Dice dices[], int sumToReach) {
int values[] = new int[dices.length];
int numberOfPairs = 0;
int left = 0;
int right = values.length - 1;
for(int i = 0; i < dices.length; i++){
values[i] = dices[i].getValue();
if(values[i] == sumToReach){
numberOfPairs++;
values[i] = 0;
}
}
Arrays.sort(values);
while (values[right] > sumToReach + values[0]) {
right--;
}
while (left < right) {
if (values[left] + values[right] == sumToReach) {
numberOfPairs++;
left++;
right--;
}
else if(values[left] + values[right] < sumToReach) {
left++;
}
else right--;
}
return numberOfPairs*sumToReach;
}
Your question can be paraphrased as "Get all possible number representations as sum of other natural numbers". Here is pretty good solution.
Explanation of the Algorithm:
Suppose the input array is [1 2 2 2 3 5]
First the program will search for grpSize 6 i.e. 6 elements that sum upto sum of 5
Then the program will search for grpSize 5 i.e. 5 elements that sum upto sum of 5
.
.
.
then the program will search for grpSize 1 i.e. 1 element that sums upto sum of 5
If a set is found then elements will be removed from the resultList
Warning: This approach is recursive, may lead to stack overflow if number of dice increases manyfold
public static boolean func(int grpSize,int sum,int index,List<Integer> resultList,ArrayList<Integer> values) {
if(grpSize==1) {
int j;
for(j = index; j < resultList.size(); j++) {
if(resultList.get(j) == sum) {
values.add(resultList.get(j));
resultList.remove(j);
return true;
}
}
}
for(; index < resultList.size(); index++) {
if(func(grpSize-1, sum-resultList.get(index), index+1, resultList, values)) {
values.add(resultList.get(index));
resultList.remove(index);
return true;
}
}
return false;
}
public static void main(String[] args) {
List<Integer> resultList = new ArrayList<>();
ArrayList<ArrayList<Integer>> values = new ArrayList<>();
resultList.add(1);
resultList.add(2);
resultList.add(2);
resultList.add(2);
resultList.add(3);
resultList.add(5);
//3 2 2 2 3 5
int sum = 5;
int n = resultList.size();
for(int i = 0; i < n; i++) {
int k=i;
while(true) {
values.add(new ArrayList<>());
func(n-i, sum, 0, resultList, values.get(values.size() - 1));
if(values.get(k).isEmpty()) {
break;
} else {
k++;
}
}
}
values.removeIf(p -> p.isEmpty());
System.out.println("Number of pairs: "+values.size());
values.forEach((it) -> {
System.out.println(it);
});
int temp = 0;
for(int i = 0; i < values.size(); i++) {
for(int j = 0; j < values.get(i).size(); j++) {
temp += values.get(i).get(j);
}
}
System.out.println("sum: "+temp);
}
}
Working of recursive function:
This function requires
Group Size to search for
The sum to search for
The starting index which is always zero(could(should) be cleaned up)
The list of each die roll
The list to add found values
This is boolean function which will return true if a particular set if found to add up to THE SUM. The concept is that of basic Backtracking
I have an array and my goal is to find out how many are spaced by multiples of 11. The array is NOT sorted.
Such as [27, 16, 52, 84], this would return 2
[1, 55, 66, 33] should return 3.
[99, 8, 52, 32] should return 0
Currently what I have is to basically run through for-each element in the array, check every other element with multiplying by 11. But this leaves me at a O(n²) runtime, anyway I can optimize this?
static int eval(int [] a) {
int i, j, k, counter = 0;
for (i = 0; i < a.length; i++) {
for (j = 0; j < a.length; j++) {
if (i != j) {
for (k = -9; k < 10; k++) {
if (a[i] == a[j] + k*11) {
counter++;
break;
}
}
}
}
}
//if found nothing, will return 0, if found 1 matching,
//it should be 2 numbers that share this 11-difference.
return counter : counter == 0? 0: counter + 1;
}
Thanks!
It's not entirely clear what the output is supposed to be for, say, [11, 22, 34, 45]. I'm interpreting the question as asking for the size of the largest subset of the input where all differences between elements of the subset are multiples of 11, and where size-1 subsets don't count.
All inputs with the same residue mod 11 are spaced by multiples of 11, so we only need to count how many ints in the input have each possible value of i % 11. This takes time linear in the size of the input.
static int eval(int[] a) {
int[] inputsPerResidue = new int[11];
for (int i : a) {
inputsPerResidue[i % 11]++;
}
int maxGroupSize = 0;
for (int groupSize : inputsPerResidue) {
if (groupSize > 1 && groupSize > maxGroupSize) {
maxGroupSize = groupSize;
}
}
return maxGroupSize;
}
You would need 2 loops to accomplish this. Calculate the difference between every element, and if that number is a multiple of 11, increment the counter. Return half the counter, as if you hit a multiple of 11 between two elements, you will end up hitting the same two elements again later in the loop:
static int eval(int [] a) {
int counter = 0;
for (int i = 0; i < a.length; i++) {
for (int j = 0; j < a.length; j++) {
if (i != j && Math.abs(a[i] - a[j]) % 11 == 0) {
counter++;
}
}
}
return counter / 2;
}
I made this method that compares the numbers of two arrays and then returns how many numbers are equal to each other, but no matter how many numbers are equal, the method returns the value 1 every time.
(both arrays are the same length).
public static void main(String[] args) {
int a [] = {1, 4, 6, 7, 8, 10, 13};
int b [] = {1, 2, 3, 4, 5, 6, 7};
equal(a,b);
}
public static int equal(int[] a, int[] b){
int j = 0;
for(int i = 0; i< a.length-1;i++){
if(a[i] == b[i]){
j++;
}
}
System.out.println(j);
return j;
}
Your code is finding the number that are equal at the same index.
There are several ways you can find the size of the intersection.
A simple but O(m*n) implementation would be to iterate over all elements of b for each element of a.
If the arrays are sorted, you could use separate indexes for the two arrays, advancing each when it can no longer match. This would be O(m+n). (If they're not sorted, you could sort them first, for a cost of O(m log m + n log n ).
If each array has no duplicate members, another way is to compute the size of the intersection is from the size of the set difference. An example of this is at http://ideone.com/6vLAfn. The key part is to convert each array to a set, and determine how many members are in common by removing one set from another.
int aSizeBefore = setA.size();
setA.removeAll( setB );
int aSizeAfter = setA.size();
return aSizeBefore - aSizeAfter;
You should use a nested for loop if you want to check if any single number in array a is also in array b.
e.g.
int numMatches = 0;
for (int i = 0; i < a.length; ++i)
{
for (int j = 0; j < b.length; ++j)
{
if (a[i] == b[j])
++numMatches; //Naive, as obviously if the same number appears twice in a it'll get counted twice each time it appears in b.
}
}
The current code just checks the elements at the same index match i.e
1 == 1 // Yes, increment j
4 == 2 // Nope
6 == 3 // Nope
7 == 4 // Nope
8 == 5 // Nope
10 == 6 // Nope
13 == 7 // Nope
Elements with same values might be in different indexes. You can write as following, assuming the arrays are sorted:
public static int equal(int[] a, int[] b) {
int count = 0;
for(int i = 0; i < a.length - 1; i++) {
for(int j = 0; i < b.length - 1; j++) {
if (a[j] < b[j]) {
// we came to the part where all elements in b are bigger
// than our selected element in a
break;
}
else if (a[j] == b[j]) {
count++;
}
}
}
System.out.println(count);
return count;
}
If you can't guarantee that the arrays are sorted, you can remove the if-block and remove the else-if's else from the loop.
If you want to know how many numbers are present in both arrays and there is a guarantee that they are ordered, you should try the following:
public static int equal(int[] a, int[] b) {
int j, result = 0;
int lastFound = 0;
for (int i = 0; i < a.length - 1; i++) {
for (j = lastFound; j < b.length; j++) {
if (a[i] == b[j]) {
result++;
lastFound = j;
break;
} else {
if (a[i] < b[j]) break;
}
}
}
return result;
}
Using the variable lastFound will speed your loops, but it is only helpful if the arrays are ordered, as your example indicates.