LeetCode 1365 - looking for a better solution than O(n^2) - java

I am working leetcode problem number 1365. Here is the problem below in italicized characters:
Given the array nums, for each nums[i] find out how many numbers in the array are smaller than it. That is, for each nums[i] you have to count the number of valid j's such that j != i and nums[j] < nums[i].
Return the answer in an array.
Example 1: Input: nums = [8,1,2,2,3] Output: [4,0,1,1,3] Explanation: For nums[0]=8 there exist four smaller numbers than it (1, 2, 2 and 3). For nums[1]=1 does not exist any smaller number than it. For nums[2]=2 there exist one smaller number than it (1). For nums[3]=2 there exist one smaller number than it (1). For nums[4]=3 there exist three smaller numbers than it (1, 2 and 2).
https://leetcode.com/problems/how-many-numbers-are-smaller-than-the-current-number/
I am able to complete the task using brute force which gives an O(n^2) time. Is there a faster way to code this problem?
public static void main(String[] args) {
int[] nums = new int[] {8,1,2,2,3};
System.out.println(Arrays.toString(smallerNumbersThanCurrent(nums)));
}
public static int[] smallerNumbersThanCurrent(int[] nums) {
int[] result = new int[nums.length];
for (int x = 0; x < nums.length; x++) {
int ctr = 0;
for (int y = 0; y < nums.length; y++) {
if (nums[y] < nums[x]) {
ctr++;
}
result[x] = ctr;
}
}
return result;
}

A simple O(nlgn) solution with an O(n) space would be:
Copy the array into a temp array, O(n)
Sort the new array O(ngln)
Iterate over the original array
For every element, do a binary search over the sorted array and get the first index of the element.
The index would be the count you are after.

There is a slightly better O(n^2) approach, where you only compare each pair of indices once and updating the counts accordingly:
public static int[] smallerNumbersThanCurrent(int[] nums)
{
int[] result = new int[nums.length];
for (int x = 0; x < nums.length; x++)
{
for (int y = x + 1; y < nums.length; y++)
{
if (nums[y] < nums[x])
result[x]++;
else if (nums[y] > nums[x])
result[y]++;
}
}
return result;
}
However, at the cost of an additional array we can do it in O(ngln) by sorting the indices of the original array and then iterating through these sorted indices, updating the count accordingly. The only complication is in dealing with repeated numbers, e.g. the 2s in your example.
public static int[] smallerNumbersThanCurrent(int[] nums)
{
Integer[] idx = new Integer[nums.length];
for(int i=0; i<idx.length; i++) idx[i] = i;
Arrays.sort(idx, (a, b) -> (nums[a]-nums[b]));
int[] res = new int[nums.length];
for(int i=1; i<idx.length; i++)
{
if(nums[idx[i]] == nums[idx[i-1]])
res[idx[i]] = res[idx[i-1]];
else
res[idx[i]] = i;
}
return res;
}
Test:
int[] nums = new int[] {8,1,2,2,3};
System.out.println(Arrays.toString(smallerNumbersThanCurrent(nums)));
Output:
[4, 0, 1, 1, 3]

Related

Ordering an Array using Another Array

I am trying to solve this LeetCode question - https://leetcode.com/problems/create-target-array-in-the-given-order/description/ where the instructions contains -
Given two arrays of integers nums and index. Your task is to create target array under the following rules:
Initially target array is empty.
From left to right read nums[i] and index[i], insert at index index[i] the value nums[i] in target array.
Repeat the previous step until there are no elements to read in nums and index.
Return the target array.
It is guaranteed that the insertion operations will be valid.
I tried out this approach but it is not working as expected.
public class LeetCode1389 {
public static void main(String[] args) {
System.out.println(Arrays.toString(createTargetArray(new int[]{0,1,2,3,4}, new int[]{0,1,2,2,1})));
}
static int[] createTargetArray(int[] nums, int[] index) {
int[] target = new int[nums.length];
for (int i = 0; i < nums.length; i++){
for (int j = 0; j < index.length; j++){
target[index[i]] = nums[i];
}
}
return target;
}
}
Use a List instead, which provides an add method to insert at a specific index. Convert the List to an int array at the end.
static int[] createTargetArray(int[] nums, int[] index) {
List<Integer> target = new ArrayList<>(nums.length);
for (int i = 0; i < nums.length; i++) target.add(index[i], nums[i]);
return target.stream().mapToInt(i -> i).toArray();
}

Generate even numbers in an int array?

For my program I need to make a 10 element array and the goal is to print out the even numbers from 2 to 20. I have to do this by adding 2 to the beginning element. This is what I have so far. I think I should use a loop as shown but I don't know how to go about adding 2 and printing that out. Thanks!
int[] array = new int[10];
for(int counter=0; counter<array.length; counter++) {
}
if you want program print even number between 2 & 20
for(int i=2;i<=20;i++)
{
if(i%2 == 0)
print(i)
}
Start at 2 and increment by 2 to get the even numbers:
int[] array = new int[10]
for(int counter=2; counter <= 20; counter += 2) {
array[counter/2 - 1] = counter
}
or
int[] array = new int[10]
for(int i=0; i <= 10; i++) {
array[i] = i*2 + 2
}
this is also an option
int i, value;
int nums[] = new int[10];
for (i = 0, value = 2; i < nums.length; value = value + 2, i = i + 1) {
nums[i] = value;
}
for (i = 0; i < nums.length; i++) {
System.out.println(nums[i]);
}
int[] array = new int[10];
for (int i = 0, j = 1; i < array.length && j <= 20; j++) {
if (j % 2 == 0) {
array[i] = j;
i++;
}
}
System.out.println(Arrays.toString(array));
Java 8: int[] array = IntStream.range(1, 11).map(x -> x * 2).toArray();
Or, to just print: IntStream.range(1, 11).map(x -> x * 2).forEach(System.out::println);
From java-9 you can use IntStream.iterate to create int array
int[] arr= IntStream.iterate(2, i->i<=20, i->i+2).toArray();
for Integer array you can use Stream.iterate
Integer[] ary = Stream.iterate(2, i->i<=20, i->i+2).toArray(Integer[]::new);
Dear Alexis,
Below is an example using do-while.
you can simply define a range of expected even numbers using minVal and maxVal.
Program will execute and return list of ordered even numbers for given range. Assuming input values are correct even numbers. You can improve to apply validations.
public class EvenNumberGenerator {
static int minVal=2; //enter valid min value even number
static int maxVal = 20; //enter valid max value even number
public static void main(String[] args) {
List<Integer> evenNumbers = new ArrayList();
do {
if(minVal % 2 == 0) {
evenNumbers.add(minVal);
}
minVal++;
} while (!evenNumbers.contains(maxVal));
System.out.println(evenNumbers);
// evenNumbers.toArray(); in case you need an array
}
}
OUTPUT
[2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
Hope it helps!
Using your code as a start, this will work:
int[] array = new int[10];
for(int counter=0; counter<array.length; counter++) {
array[counter] = (counter + 1) * 2;
}
System.out.println(Arrays.toString(array));
The following will also work with Eclipse Collections:
int[] array = IntInterval.evensFromTo(2, 20).toArray();
System.out.println(Arrays.toString(array));
Note: I am a committer for Eclipse Collections

Looking for efficient way of splitting array into k-arrays

I am trying to create a program that takes an integer array in increasing order and split it into k non-empty arrays in increasing order which when combined into a single array produce the original array - the first array cannot contain any but the first or more digits (k1=[1,2,3] is valid but k1=[2,3,4] is not)
So far I have tried given a array[4,7,11,21,31] and k=3 hard-coding two for-loops that act as pointers on where to copy the items and copying part of the original array into the respected variables
int[] array = {1,2,3,4,5};
int k = 3;
int n = 5;
for(int i = 0; i <= n - k; i++){
for(int j = i+1; j < n-1; j++){
int[] k1 = Arrays.copyOfRange(array , 0, i+1);
int[] k2 = Arrays.copyOfRange(array , i+1, j+1);
int[] k3 = Arrays.copyOfRange(array , j+1, n);
}
}
The above code works for k=3 but the problem is that I do not know how to efficiently make it work for any k and efficiently store the arrays
The end goal is to generate all possible combinations
This recursive brute-force approach doesn't really split an array of numbers, it just returns the indices of the array entries where the splits have to happen.
It takes two arguments:
n the length of the array
k the number of parts wanted
It will return an ArrayList<int[]> that contains all possible combinations of splits (each of those as an array of indices with k-1 elements in ascending order).
I have tried some cases and it seems to work. As expected, it always seems to return the binomial coefficient (n-1) over (k-1) amount of combinations. This is because in any array with length n there are n-1 places where it could be split into two. We only want to split it k-1 times, though (to end up with k parts). So this is basically selecting k-1 from n-1, thus the binomial coefficient.
public static ArrayList<int[]> getSplits(int n, int k) {
if (k == 1) {
return new ArrayList<int[]>();
}
ArrayList<int[]> newSplits = new ArrayList<int[]>();
for (int s = 1; s < n-(k-1)+1; s++) {
if (k == 2) {
newSplits.add(new int[] {s});
} else {
ArrayList<int[]> splits = getSplits(n-s, k-1);
for (int[] split : splits) {
int[] newSplit = new int[split.length + 1];
newSplit[0] = s;
for (int i = 0; i < split.length; i++) {
newSplit[i+1] = split[i] + s;
}
newSplits.add(newSplit);
}
}
}
return newSplits;
}
Used in the context of your question:
To get your array parts from this, you can use this function. It outputs them separated by pipe symbols (|).
public static void main(String args[]) {
int[] array = new int[] {1, 2, 3, 4};
int n = array.length;
int k = 3;
ArrayList<int[]> splits = getSplits(n, k);
for (int[] split : splits) {
int j = 0;
for (int i = 0; i < split.length; i++) {
for (; j < split[i]; j++) {
System.out.print(array[j] + " ");
}
System.out.print("| ");
}
for (; j < n; j++) {
System.out.print(array[j] + " ");
}
System.out.println();
}
}
This prints the following (all possibilites to split 4 items into 3 non-empty groups):
1 | 2 | 3 4
1 | 2 3 | 4
1 2 | 3 | 4

Given two sorted lists (or arrays) and a number k, create an algorithm to fetch the least k numbers of the two lists

Need to find the first 3 smallest number in given two sorted array. I supposed that two array should merge into one first and sort it in order to fetch the first 3 smallest number. Can anyone help me with the merge and sort part or provide some advice, any help will appreciate.
This is where i reached now, I only can get the smallest number ( not first 3, just one).
public class MergeandSort {
public static void main(String[] args) {
int[] set1 = {1,2,6,9,18};
int[] set2 = {2,3,7,10,21,30};
int smallest = set1[0];
int smallests = set2[0];
for(int i=0; i < set1.length; i++){
if(set1[i] < smallest)
smallest = set1[i];
}
for(int k=0; k < set2.length; k++){
if(set2[k] < smallests)
smallests = set2[k];
}
System.out.println("Smallest Number in Set 1 is : " + smallest);
System.out.println("Smallest Number in Set 2 is : " + smallests);
}
}
The arrays are already sorted, so you don't have to iterate over the entire arrays to find the 3 smallest numbers.
You just have to start iterating over both arrays at the same time (i.e. in the same loop).
In each iteration you compare the current two elements of the two arrays (starting at the 2 elements at the 0 index) and take the smaller of them
Then you advance the index of the array from which you took the smallest number.
Once you reach 3 elements (after 3 iterations), you break out of the loop.
Here's some pseudo code to get you started:
int i = 0;
int j = 0;
int c = 0;
int[] lowest3 = new int[3];
while (true) {
find the smaller of set1[i] and set2[j] and put it in lowest3[c]
if set1[i] is smaller, increment i
otherwise increment j
increment c
if (c==3) // you are done
break;
}
the lowest3 array now contains the 3 lowest numbers of both arrays
Of course you can swap 3 with any k. You just have to make sure that i is always smaller than set1.length and j is always smaller than set2.length.
If the arrays are already sorted, just implement the merging technique of merge sort with the limitation in while condition that it should run only k times (in this case 3), but dont forget to check that size of sets are less than k or not!
int k = 0,i = 0,j = 0;
while (k<3 && k<set1.length && k<set2.length )
{
if (set1[i] <= set2[j])
{
final_set[k] = set1[i];
i++;
}
else
{
final_set[k] = set2[j];
j++;
}
k++;
}
while (k<3 && k<set1.length) {
final_set[k]=set1[i];
k++;
i++;
}
while (k<3 && k<set2.length) {
final_set[k]=set1[j];
k++;
j++;
}
public class MergeandSort {
public static void main(String[] args) {
int[] set1 = {1,2,6,9,18};
int[] set2 = {2,3,7,10,21,30};
int[] sorted = new int[k];
int smallest = set1[0];
int smallests = set2[0];
int i = 0, j = 0, c = 0;
while(i < set1.length && j < set2.length && c < k){
if (set1[i] < set2[j])
sorted[c++] = arr1[i++];
else
sorted[c++] = arr2[j++];
while (i < set1.length && c < k)
sorted[c++] = arr1[i++];
while (j < set2.length && c < k)
sorted[c++] = arr2[j++];
System.out.println(sorted);
}
}
where k is the count of sorted numbers you want
That would not work as:
Array1 = {1,3,5}
Array2 = {2,3,4}
Correct solution: {1,2,3}
Output of your solution: {1,3,4}

return an Array which contains only odd integers

Ok, so I have this problem where when given an Array arr, return an Array which contains only odd integers in the original order from arr.
My code:
public int [] youMakeMeOdd(int [] arr)
{
int[] odds;
odds = new int[arr.length];
for(int i = 0; i < arr.length; i++)
{
if(arr[i] % 2 != 0)
{
odds[i] = arr[i];
}
}
return odds;
}
Few Testers:
Expected...........................................................Run:
youMakeMeOdd({1,2,3}) → {1, 3}.....................{1, 0, 3}
youMakeMeOdd({2,1,3,5,7}) → {1, 3, 5, 7}.......{0, 1, 3, 5, 7}
youMakeMeOdd({2,4,6,8}) → {}........................{0, 0, 0, 0}
.
I can't seem to figure out how to put a blank space there instead of 0's. Help appreciated, thanks :)
The output array is being initialized to the size of the input array. I guess this being java code, the array elements are initialized to zero by default. So whenever the if condition does skips the ith position the default value (zero) is being shown.
public int[] youMakeMeOdd(int [] arr) {
List<Integer> odds = new ArrayList<Integer>();
for(int i = 0; i < arr.length; i++)
{
if(arr[i] % 2 != 0)
{
odds.add(arr[i]);
}
}
return convertIntegers(odds);
}
public static int[] convertIntegers(List<Integer> integers)
{
int[] ret = new int[integers.size()];
Iterator<Integer> iterator = integers.iterator();
for (int i = 0; i < ret.length; i++)
{
ret[i] = iterator.next().intValue();
}
return ret;
}
You could have a pre-computation loop where you just increment a counter and then allocate odds:
int counter = 0;
for (int i = 0; i < arr.length; i++)
{
if (arr[i] % 2 != 0)
{
counter ++;
}
}
odds = new int[counter];
I would use an ArrayList. Your problems seems to be the fact that arrays are immutable, so you it automatically fills your array with a bunch of unneeded 0s. ArrayLists can change dimensions, so you don't have to have the 0s.
You can have a look at them here: http://docs.oracle.com/javase/7/docs/api/java/util/ArrayList.html
Make sure you import the util package.
import java.util.*;
public ArrayList<Integer> youMakeMeOdd(int [] arr)
{
You need to specify the type that you want to hold in the angle braces. Because int is a primitive, you need to use the Integer class
ArrayList<Integer> odds;
odds = new ArrayList<>();
for(int i = 0; i < arr.length; i++)
{
if(arr[i] % 2 != 0)
{
The add method adds an integer to the end
odds.add(new Integer(arr[i]));
}
}
return odds;
}
var result = input.Select(a=>a % 2 != 0 ? a : 0).ToArray()
You can use linq easily, basically you use the original array and then use the Select to select either the value itself of the array or 0 if it's even, and then convert to an array using ToArray method.

Categories