What is map[(int)x]++;What it does? - java

Hey I took part in Facebook Hacker Competition and I got a solution of this question.
I solved th question in order O(K^2) but this guy solved it in O(^K).
Please explain me what the code doing.
import java.io.File;
import java.util.Scanner;
public class FindTheMin {
private long getNextMin(long[] map, long start, long k) {
while (map[(int)(start)] > 0)
start++;
return start;
}
public long findNth(long n, long k, long a, long b, long c, long r) {
long[] cache = new long[100010];
long[] map = new long[100010];
long pre = a;
for (int i = 0; i < k; i++) {
long num;
if (i == 0)
num = a;
else
num = (b * pre + c) % r;
cache[i] = num;
if (num <= k + 1)
map[(int) num]++;
pre = num;
}
pre = getNextMin(map, 0, k);
cache[(int)k] = pre;
map[(int)pre]++;
for (int i = 0; i <= (int)k; i++) {
long deque = cache[i];
if (deque > k) {
long x = getNextMin(map, pre, k);
cache[i] = x;
map[(int)x]++;
pre = x;
} else {
if (deque < pre) {
if(map[(int)deque] == 1) {
cache[i] = deque;
pre = deque;
continue;
}
}
map[(int)deque]--;
long x = getNextMin(map, pre, k);
cache[i] = x;
pre = x;
map[(int)x]++;
}
}
return cache[(int)((n - 1) % (k + 1))];
}
public static void main(String[] args) {
try {
Scanner s = new Scanner(new File("in.txt"));
int m = s.nextInt();
FindTheMin f = new FindTheMin();
for (int i = 1; i <= m; i++) {
int n, k, a, b, c, r;
n = s.nextInt();
k = s.nextInt();
a = s.nextInt();
b = s.nextInt();
c = s.nextInt();
r = s.nextInt();
System.out.println("Case #" + i + ": " + f.findNth(n, k, a, b, c, r));
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
And what are the best ways to learn things like this. the best way to learn java?
This was the question
https://www.facebook.com/hackercup/problems.php?pid=494433657264959&round=185564241586420

map[(int)x]++ does the same as the following:
int index = (int) x;
map[index]++;

What is map[(int)x]++;What it does?
arrays in java accepts only an integer index, but x in your code is a long value.
therefore it has to be casted to int:
This code gets element at index x from array map and adds 1 to the value:
same as:
map[ix]++; // where ix = (int) x;
Question 2:
And what are the best ways to learn things like this. the best way to learn java?
Buy, read and understand:
Robert Sedgewick, Algorithms Fourth Edition

In
long x = getNextMin(map, pre, k);
cache[i] = x;
map[(int)x]++;
While x is a long, the indexes of an array may only be int. Furthermore, and more importantly, although getNextMin is returning a long, the programmer knows the value is actually an int (i.e. x <= Integer.MAX_VALUE) otherwise there could be possible overflow resulting in a negative value for x which would cause an ArrayIndexOutOfBoundsException exception.
Now because java is statically typed, although the value returned by getNextMin fits into an int, you still must tell the compiler your intention to use it as an int; otherwise the compiler will assume it's a long. That is why you see (int)x -- since array indices must be of type int
For the code itself
map[(int)x]++;
could be written as
map[(int)x] = map[(int)x] + 1;
or as
int y = (int) x
map[y]++; // or as map[y] = map[y] + 1
Again, if the value returned by getNextMin is greater than Integer.MAX_VALUE the code will throw an exception. And so it may be a design flaw that the programmer is not handling the potential exception.

Related

Determining if a program is fast, memory-efficient and does not have large time-complexity

Could someone please help me how I could determine whether my program is memory-efficient, fast and has low time-complexity? For one of my programs, I implemented merge sort and then called some methods here and there but since it has around 100 lines of code, I am skeptical whether it is memory efficient. Thanks guys
import java.util.*;
public class Question6 {
static void mergeSort(Integer arr1[], int o, int k, int x) {
int num1 = k - o + 1;
int num2 = x - k;
int temp1[] = new int[num1]; //creation of two temporary arrays to store in
int temp2[] = new int[num2];
for (int i = 0; i < num1; ++i) //for loops to copy the data to the temporary arrays
temp1[i] = arr1[o + i];
for (int j = 0; j < num2; ++j)
temp2[j] = arr1[k + 1 + j];
int i = 0, j = 0; //starting position of temporary arrays
int s = o; //starting position of the merged two temporary arrays
while (i < num1 && j < num2) {
if (temp1[i] <= temp2[j]) {
arr1[s] = temp1[i];
i++;
} else {
arr1[s] = temp2[j];
j++;
}
s++;
}
//code to copy elements from temp1
while (i < num1) {
arr1[s] = temp1[i];
i++;
s++;
}
//code to copy elements from temp2
while (j < num2) {
arr1[s] = temp2[j];
j++;
s++;
}
}
void forSorting(Integer arr2[], Integer t, Integer x) //main method that carries out merge sort
{
if (t < x) {
// Find the middle point
Integer a = (t + x) / 2;
// Sort first and second halves
forSorting(arr2, t, a);
forSorting(arr2, a + 1, x);
// Merge the sorted halves
mergeSort(arr2, t, a, x);
}
}
public static void main(String[] args) {
Question6 qs = new Question6();
Scanner sc = new Scanner(System.in);
Integer[] duplicate = new Integer[10];
System.out.println("Please input the numbers to be checked for repetition.");
for (int x = 0; x < 10; x++) {
duplicate[x] = sc.nextInt(); //filling array
}
int length = duplicate.length;
qs.forSorting(duplicate, 0, length - 1); //calling method forSorting
System.out.println(Arrays.toString(duplicate)); //displays the array which user fills
List<Integer> list = Arrays.asList(duplicate); //makes the array duplicate available as a list
Set<Integer> set = new LinkedHashSet<Integer>(list);
for ( Integer element : set) {
if(Collections.frequency(list, element) > 1) {
System.out.println(" Duplicate: " + element);
}
}
}
}
You can use Profiler. For Java - JProfiler, VisualVM, etc. You can check there all you looking for - how much memory yours algorithms need, the time complexity, and some more stuff.

difficulty with fibonacci function

I'm supposed to change this recursive function, into an iterative function...
int rFib(int n)
{ //assumes n >= 0
if(n <= 1)
return n;
else
return (rFib(n-1) + rFib(n-2));
}
But I'm drawing a blank on the mathematical view of this... I would appreciate any assistance. I was able to get the other 3 functions, but I just can't seem to figure out the math of this one.
public static int fib(int n)
{
int theFib = 1;
while(n > 1)
{
theFib = n - 1;
n = n + n - 2;
}
System.out.println(theFib);
return theFib;
}
The next number in the Fibonacci sequence is the sum of the last two numbers, so you'll need to remember the last two numbers.
In pseudo code, since you should do some of the homework yourself:
n1 = 0
n2 = 1
loop
n = n1 + n2
n1 = n2
n2 = n
end loop
I'll leave it to you to limit the looping.
You can find an example here.
The code in question:
public class FibonacciIterative {
public static int fib(int n) {
int prev1=0, prev2=1;
for(int i=0; i<n; i++) {
int savePrev1 = prev1;
prev1 = prev2;
prev2 = savePrev1 + prev2;
}
return prev1;
}
}
It does not really matter which direction (up or down) you count. The challenge is to deal with the limits properly.
Using dynamic programming technique:
static int fib(int n) {
int[] fibs = new int[n + 1];
for (int i = 0; i <= n; i++) {
if (i <= 1) {
fibs[i] = i;
} else {
fibs[i] = fibs[i - 1] + fibs[i - 2];
}
}
return fibs[n];
}

NumberOfDiscIntersections overflow in codility test

In the codility test NumberOfDiscIntersections I am getting perf 100% and correctness 87% with the one test failing being
overflow
arithmetic overflow tests
got -1 expected 2
I can't see what is causing that given that I am using long which is 64-bit. And even if I can get it to 100% perf 100% correctness I am wondering if there is a better way to do this that is not as verbose in Java.
edit: figured out a much better way to do with with two arrays rather than a pair class
// you can also use imports, for example:
import java.util.*;
// you can use System.out.println for debugging purposes, e.g.
// System.out.println("this is a debug message");
class Solution {
public int solution(int[] A) {
int j = 0;
Pair[] arr = new Pair[A.length * 2];
for (int i = 0; i < A.length; i++) {
Pair s = new Pair(i - A[i], true);
arr[j] = s;
j++;
Pair e = new Pair(i + A[i], false);
arr[j] = e;
j++;
}
Arrays.sort(arr, new Pair(0, true));
long numIntersect = 0;
long currentCount = 0;
for (Pair p: arr) {
if (p.start) {
numIntersect += currentCount;
if (numIntersect > 10000000) {
return -1;
}
currentCount++;
} else {
currentCount--;
}
}
return (int) numIntersect;
}
static private class Pair implements Comparator<Pair> {
private long x;
private boolean start;
public Pair(long x, boolean start) {
this.x = x;
this.start = start;
}
public int compare(Pair p1, Pair p2) {
if (p1.x < p2.x) {
return -1;
} else if (p1.x > p2.x) {
return 1;
} else {
if (p1.start && p2.start == false) {
return -1;
} else if (p1.start == false && p2.start) {
return 1;
} else {
return 0;
}
}
}
}
}
Look at this line:
Pair s = new Pair(i + A[i], true);
This is equivalent with Pair s = new Pair((long)(i + A[i]) , true);
As i is integer, and A[i] is also integer, so this can cause overflow, as value in A[i] can go up to Integer.MAX_VALUE, and the cast to long happened after add operation is completed.
To fix:
Pair s = new Pair((long)i + (long)A[i], true);
Note: I have submitted with my fixed and got 100%
https://codility.com/demo/results/demoRRBY3Q-UXH/
My todays solution. O(N) time complexity. Simple assumption that number of availble pairs in next point of the table is difference between total open circle to that moment (circle) and circles that have been processed before. Maybe it's to simple :)
public int solution04(int[] A) {
final int N = A.length;
final int M = N + 2;
int[] left = new int[M]; // values of nb of "left" edges of the circles in that point
int[] sleft = new int[M]; // prefix sum of left[]
int il, ir; // index of the "left" and of the "right" edge of the circle
for (int i = 0; i < N; i++) { // counting left edges
il = tl(i, A);
left[il]++;
}
sleft[0] = left[0];
for (int i = 1; i < M; i++) {// counting prefix sums for future use
sleft[i]=sleft[i-1]+left[i];
}
int o, pairs, total_p = 0, total_used=0;
for (int i = 0; i < N; i++) { // counting pairs
ir = tr(i, A, M);
o = sleft[ir]; // nb of open till right edge
pairs = o -1 - total_used;
total_used++;
total_p += pairs;
}
if(total_p > 10000000){
total_p = -1;
}
return total_p;
}
int tl(int i, int[] A){
int tl = i - A[i]; // index of "begin" of the circle
if (tl < 0) {
tl = 0;
} else {
tl = i - A[i] + 1;
}
return tl;
}
int tr(int i, int[] A, int M){
int tr; // index of "end" of the circle
if (Integer.MAX_VALUE - i < A[i] || i + A[i] >= M - 1) {
tr = M - 1;
} else {
tr = i + A[i] + 1;
}
return tr;
}
My take on this, O(n):
public int solution(int[] A) {
int[] startPoints = new int[A.length];
int[] endPoints = new int[A.length];
int tempPoint;
int currOpenCircles = 0;
long pairs = 0;
//sum of starting and end points - how many circles open and close at each index?
for(int i = 0; i < A.length; i++){
tempPoint = i - A[i];
startPoints[tempPoint < 0 ? 0 : tempPoint]++;
tempPoint = i + A[i];
if(A[i] < A.length && tempPoint < A.length) //first prevents int overflow, second chooses correct point
endPoints[tempPoint]++;
}
//find all pairs of new circles (combinations), then make pairs with exiting circles (multiplication)
for(int i = 0; i < A.length; i++){
if(startPoints[i] >= 2)
pairs += (startPoints[i] * (startPoints[i] - 1)) / 2;
pairs += currOpenCircles * startPoints[i];
currOpenCircles += startPoints[i];
currOpenCircles -= endPoints[i];
if(pairs > 10000000)
return -1;
}
return (int) pairs;
}
The explanation to Helsing's solution part:
if(startPoints[i] >= 2) pairs += (startPoints[i] * (startPoints[i] - 1)) / 2;
is based on mathematical combinations formula:
Cn,m = n! / ((n-m)!.m!
for pairs, m=2 then:
Cn,2 = n! / ((n-2)!.2
Equal to:
Cn,2 = n.(n-1).(n-2)! / ((n-2)!.2
By simplification:
Cn,2 = n.(n-1) / 2
Not a very good performance, but using streams.
List<Long> list = IntStream.range(0, A.length).mapToObj(i -> Arrays.asList((long) i - A[i], (long) i + A[i]))
.sorted((o1, o2) -> {
int f = o1.get(0).compareTo(o2.get(0));
return f == 0 ? o1.get(1).compareTo(o2.get(1)) : f;
})
.collect(ArrayList<Long>::new,
(acc, val) -> {
if (acc.isEmpty()) {
acc.add(0l);
acc.add(val.get(1));
} else {
Iterator it = acc.iterator();
it.next();
while (it.hasNext()) {
long el = (long) it.next();
if (val.get(0) <= el) {
long count = acc.get(0);
acc.set(0, ++count);
} else {
it.remove();
}
}
acc.add(val.get(1));
}
},
ArrayList::addAll);
return (int) (list.isEmpty() ? 0 : list.get(0) > 10000000 ? -1 : list.get(0));
This one in Python passed all "Correctness tests" and failed all "Performance tests" due to O(n²), so I got 50% score. But it is very simple to understand. I just used the right radius (maximum) and checked if it was bigger or equal to the left radius (minimum) of the next circles. I also avoided to use sort and did not check twice the same circle. Later I will try to improve performance, but the problem here for me was the algorithm. I tried to find a very easy solution to help explain the concept. Maybe this will help someone.
def solution(A):
n = len(A)
cnt = 0
for j in range(1,n):
for i in range(n-j):
if(i+A[i]>=i+j-A[i+j]):
cnt+=1
if(cnt>1e7):
return -1
return cnt

Java IF Statement (Algorithm efficiency improvement)

I used method a that counts the amount of possible choices for getting like number 10 with numbers that are from 0 to 6. Problem is that it just takes too much time when x is like 50 or something. I just need some tips what I should do to make this faster.
Code
public static int count(int x) {
if (x < 0) {
return 0;
}
if (x == 0) {
return 1;
}
int result = 0;
for (int i = 1; i <= 6; i++) {
result += count(x - i);
}
return result;
}
This is a variation on Fibonacci except it is the sum of the last six values instead.
You can use a plain loop which will be faster than memorisation (the first time)
public static long count(int x) {
long a=0, b=0, c=0, d=0, e=0, f=1;
while(x-- > 0) {
long sum = a + b + c + d + e + f;
a = b; b = c; c = d; d = e; e = f;
f = sum;
}
return f;
}
If you call this repeatedly you may as well store all the values in the int range which is likely to be less than 30 the first time and retrieve these values after that.

Sum of Powers of two Integers using only For-Loops

The question here would be to get the sum of powers (m^0 + m^1 + m^2 + m^3.... + m^n) using only FOR loops. Meaning, not using any other loops as well as Math.pow();
Is it even possible? So far, I am only able to work around getting m^n, but not the rest.
public static void main(String[] args){
Scanner scn = new Scanner(System.in);
int total = 1;
System.out.print("Enter value of m: ");
int m = scn.nextInt();
System.out.print("Enter value of n: ");
int n = scn.nextInt();
for (int i = 1; i <= n; i++){
total * m;
}
System.out.print(total);
}
Let's say m =8; and n = 4;
i gives me '1,2,3,4' which is what I need, but I am unable to power m ^ i.
Would be nice if someone could guide me into how it could be done, can't seem to progress onwards as I have limited knowledge in Java.
Thanks in advance!
You might want to rewrite it like this :
m^0 + m^1 + m^2 + m^3.... + m^n = 1 + m * (1 + m * (1 + m * (.... ) ) )
And you do it in a single for loop.
This should do the job (see explanations in comments):
public long count(long m, int pow) {
long result = 1;
for(int i = 0;i<pow; i++) {
result*=m +1;
}
return result;
}
You can nest loops. Use one to compute the powers and another to sum them.
You can do below:
int mul = 1;
total = 1;
for(int i=1;i<=n;i++) {
mul *= m;
total += mul;
}
System.out.println(total);
You can use a single loop which is O(N) instead of nested loops which is O(N^2)
long total = 1, power = m
for (int i = 1; i <= n; i++){
total += power;
power *= m;
}
System.out.print(total);
You can also use the formula for geometric series:
Sum[i = k..k+n](a^i) = (a^k - a^(k+n+1)) / (1 - a)
= a^k * (1 - a^(n+1)) / (1 - a)
With this, the implementation can be done in a single for loop (or 2 simple for loop): either with O(n) simple looping, or with O(log n) exponentiation by squaring.
However, the drawback is that the data type must be able to hold at least (1 - a^(n+1)), while summing up normally only requires the result to fit in the data type.
This is the solution :
for(int i=0;i<n;i++){
temp=1;
for(int j=0;j<=i;j++){
temp *= m;
}
total += temp;
}
System.out.println(total+1);
You can easily calculate powers using your own pow function, something like:
private static long power(int a, int b) {
if (b < 0) {
throw new UnsupportedOperationException("Negative powers not supported.");
}
if (b == 0) {
return 1;
}
if (b == 1) {
return a;
}
return a * power(a, b - 1);
}
Then simply loop over all the values and add them up:
long out = 0;
for (int i = 0; i <= n; ++i) {
out += power(m, i);
}
System.out.println(out);
I would add that this is a classic dynamic programming problem as m^n is m * m^(n-1). I would therefore add caching of previously calculated powers so that you don't have to recalculate.
private static Map<Integer, Long> powers;
public static void main(String args[]) {
int m = 4;
int n = 4;
powers = new HashMap<>();
long out = 0;
for (int i = 0; i <= n; ++i) {
out += power(m, i);
}
System.out.println(out);
System.out.println(powers);
}
private static long power(int a, int b) {
if (b < 0) {
throw new UnsupportedOperationException("Negative powers not supported.");
}
if (b == 0) {
return 1;
}
if (b == 1) {
return a;
}
Long power = powers.get(b);
if (power == null) {
power = a * power(a, b - 1);
powers.put(b, power);
}
return power;
}
This caches calculated values so that you only calculate the next multiple each time.

Categories

Resources