I am practicing Algorithms question on merge sort. I build a java program on merge sort. I think there is some logical error in my code.
This is my output:
Array length = 6
value of q 2
value of q 1
value of q 0
9 1073741823 left end -----m(0,0,1)
6 1073741823 right end -----m(0,0,1)
remaining element left
6 9 0 0 0 0 -------------------
9 6 1073741823 left end -----m(0,1,2)
5 1073741823 right end -----m(0,1,2)
remaining element left
5 9 6 0 0 0 -------------------
value of q 4
value of q 3
0 1073741823 left end -----m(3,3,4)
8 1073741823 right end -----m(3,3,4)
remaining element right
5 9 6 0 8 0 -------------------
0 8 1073741823 left end -----m(3,4,5)
2 1073741823 right end -----m(3,4,5)
remaining element left
5 9 6 0 2 8 -------------------
9 6 5 1073741823 left end -----m(0,2,5)
0 8 2 1073741823 right end -----m(0,2,5
remaining element left
0 8 2 9 6 5 -------------------
0 8 2 9 6 5
This is my code:
public class MergeSort{
private int[] digits;
private static int[] dummy;
private int length;
public static void main(String[] args) {
int [] digits = {9,6,5,0,8,2};
System.out.println("Array length = "+digits.length);
MergeSort ms = new MergeSort();
ms.sort(digits);
for(int a :dummy){
System.out.print(a+" ");
}
}
void sort(int [] digits){
this.digits=digits;
length=digits.length;
dummy= new int[length];
mergesort(0,length-1);
}
void mergesort(int p,int r){
int q;
if(p < r){
q = (p + r) / 2;
System.out.println("value of q "+q);
mergesort(p,q);
mergesort(q+1,r);
merge(p,q,r);
System.out.println("-------------------");
}
}
void merge(int p,int q,int r){
int i,j,k;
int n1=q-p+1;
int n2 =r-q;
int [] left = new int[n1+1];
int [] right = new int[n2+1];
int [] arr=new int[n1+n2];
for(i = 0; i<n1;i++){
left[i]= digits[p+i];
//System.out.print(left[i]+" ");
}
for(j = 0; j < n2; j++){
right[j]= digits[q+j+1];
//System.out.print(left[j]+" ");
}
left[n1] = Integer.MAX_VALUE / 2;
right[n2] = Integer.MAX_VALUE / 2;
for(i = 0; i < left.length; i++){
System.out.print(left[i] + " ");
}
System.out.println("left end -----m("+p+","+q+","+r+")");
for(j = 0; j < right.length; j++){
System.out.print(right[j]+" ");
}
System.out.println("right end -----m("+p+","+q+","+r+")");
i=0;
j=0;
for(k = p; k < r; k++){
if(left[i]<right[j]){
dummy[k]=left[i];
i++;
}
else {
dummy[k] = right[j];
j++;
}
}
while(i<n1)
dummy[k]=left[i];
i++;
k++;
System.out.println("remaining element left");
}
while(j<n2){
dummy[k]=right[j];
j++;
k++;
System.out.println("remaining element right");
}
for(int a: dummy){
System.out.print(a+" ");
}
}
}
For merge sort to work it needs to take results of previews smaller calculation and use them for next stage of calculation but your results are stored in dummy that is never used as source for the next calculation only as storage. I would sugest to make merge and mergeSort functions return values it is much more readable and cleaner here is my version if you want
public class MergeSort {
public static void main(String ...args){
int[]array = {9,6,5,0,8,2};
String sortedResultToPrint = Arrays.toString(sort(array));
System.out.println(sortedResultToPrint);
}
public static int[] sort(int[] array) {
int[] result = mergSort(array, 0, array.length-1);
return result;
}
private static int[] mergSort(int[] array, int start, int end) {
int[] result = null;
if (start < end) {
int midle = (start + end) / 2;
int[] left = mergSort(array, start, midle);
int[] right = mergSort(array, midle + 1, end);
result = merge(left, right);
} else {
result = new int[]{array[start]};
}
return result;
}
private static int[] merge(int[] left, int[] right) {
int[] result = new int[left.length + right.length];
int leftPtr = 0;
int rightPtr = 0;
for (int i = 0; i < result.length; i++) {
// Copyed all the left part only right remains
if (leftPtr >= left.length) {
result[i] = right[rightPtr++];
}
// Copyed all the right part only left remains
else if (rightPtr >= right.length) {
result[i] = left[leftPtr++];
}
//Right is smaller than left
else if (right[rightPtr] < left[leftPtr]) {
result[i] = right[rightPtr++];
}
// Left is smaller than right
else {
result[i] = left[leftPtr++];
}
}
return result;
}
}
Related
I am trying to find the farthest distance between two non -overlapping intervals represented as arraylist . Non-overlapping intervals are those in which the next start point does not lie between the starting point(inclusive) and ending point(exclusive) .
Example
Number of intervals 3
Interval 1 : 1 2
Interval 2: 3 5
Interval 3: 6 7
The pair of interval (1,2) and (6,7) is farthest as distance between these two is 6 -2 = 4
So output should be 4
My implementation
import java.util.*;
class Checker implements Comparator<ArrayList>{
public int compare(ArrayList a, ArrayList b){
int x = (Integer)a.get(0);
int y = (Integer)b.get(0);
return x-y;
}
}
class OverlappingIntervals {
public static void main(String args[]) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
ArrayList<ArrayList<Integer>> intervals = new ArrayList<ArrayList<Integer>>(n);
for (int i = 0; i < n; i++) {
int x = sc.nextInt();
int y = sc.nextInt();
intervals.add(new ArrayList<Integer>(Arrays.asList(x, y)));
}
int result = overlappingIntervals(n, intervals);
System.out.println(result);
}
static int overlappingIntervals(int n, ArrayList<ArrayList<Integer>> intervals) {
// System.out.println(intervals);
Checker check = new Checker();
Collections.sort(intervals, check);
int ans = -1;
for(int i = 0; i < n-1;i++){
for(int j = i+1; j < n;j++){
int x = (Integer)intervals.get(j).get(0)- intervals.get(i).get(1);
if(x >= 0){
if(x > ans)
ans = Math.max(x,ans);
}
}
}
return ans;
}
}
Any better optimization for the above so to handle the constraints
1<=N<=10^5
1<=l<=r<=10^6
l and r is the starting point and ending point of interval respectively.
Try this.
Scanner in = new Scanner("3 1 2 3 5 6 7");
int n = in.nextInt();
int minTo = Integer.MAX_VALUE;
int maxFrom = Integer.MIN_VALUE;
for (int i = 0; i < n; ++i) {
maxFrom = Math.max(maxFrom, in.nextInt());
minTo = Math.min(minTo, in.nextInt());
}
if (minTo < maxFrom)
System.out.println("max disntance = " + (maxFrom - minTo));
else
System.out.println("none");
output:
max disntance = 4
We can solve this easily using Stack in O(n) + O(n*log(n)) Time & O(n) Space complexity.
The idea here is to merge the intervals and then check the corresponding gaps between the consecutive Intervals.
Here is an easy and classic approach to your problem with an illustration:
import java.util.*;
class OverlappingIntervals
{
public static void main(String args[])
{
Scanner sc = new Scanner(System.in);
//int n = sc.nextInt();
ArrayList<Interval> intervals = new ArrayList<>();
intervals.add(new Interval(5, 14));intervals.add(new Interval(6, 9));
intervals.add(new Interval(8, 17));intervals.add(new Interval(23, 25));
intervals.add(new Interval(36, 56));intervals.add(new Interval(33, 45));
intervals.add(new Interval(42, 67));intervals.add(new Interval(50, 69));
intervals.add(new Interval(81, 95));intervals.add(new Interval(99, 111));
int result = overlappingIntervals(intervals);
System.out.println(result); // 82 b/w [5 , 17] & [99 , 111]
}
static int overlappingIntervals(ArrayList<Interval> intervals)
{
// Sorting all Intervals based on there `start` time
Collections.sort(intervals, Comparator.comparingInt(a -> a.begin));
int maxDistance = -1;
Stack<Interval> stack = new Stack<>();
for (Interval currInterval : intervals)
{
// Pushing a non-overlapping Interval
if (stack.empty() || stack.peek().end < currInterval.begin)
stack.push(currInterval);
// Merging an overlapping Interval
if (stack.peek().end < currInterval.end)
stack.peek().end = currInterval.end;
}
/* Now, Stack will have following merged Intervals:
[5 , 17] <6> [23 , 25] <8> [33 , 69] <12> [81 , 95] <4> [99 , 111] */
// Checking the gap b/w consecutive Merged-Intervals :
Interval rightEnd = stack.pop();
if (stack.empty()) return -1;
Interval leftEnd = rightEnd;
while (!stack.empty())
leftEnd = stack.pop();
maxDistance = rightEnd.begin - leftEnd.end;
return maxDistance;
}
}
class Interval
{
int begin, end;
Interval(int begin, int end)
{
this.begin = begin; this.end = end;
}
#Override
public String toString()
{ return "[" +begin+ " , " +end+ "]"; }
}
/** [5========17] [23=25] [33=================================69] [81===========95] [99======111]
* 5-------14 23---25 36-----------------56 81------------95
* 6---9 42----------------------67 99------111
* 8------17 33----------45 50----------------69 */
We can even do this without merging the intervals but I believe this approach is easier to understand.
Feel free to ask any doubts.
This is my solution though in C++ can be easily written in any language.
T.C - O(n + log(n))
S.C - O(1)
int overlappingIntervals(int n, vector<pair<int, int> >& intervals){
sort(intervals.begin(),intervals.end());
int mi = INT_MAX;
for(auto it: intervals){
mi = min(it.second,mi);
}
return (intervals[n-1].first < mi ? -1 : intervals[n-1].first - mi);
}
I have this question I am trying to solve. I have tried coding for the past 4 hours.
An integer is defined to be a Smart number if it is an element in the infinite sequence
1, 2, 4, 7, 11, 16 …
Note that 2-1=1, 4-2=2, 7-4=3, 11-7=4, 16-11=5 so for k>1, the kth element of the sequence is equal to the k-1th element + k-1. For example, for k=6, 16 is the kth element and is equal to 11 (the k-1th element) + 5 ( k-1).
Write function named isSmart that returns 1 if its argument is a Smart number, otherwise it returns 0. So isSmart(11) returns 1, isSmart(22) returns 1 and isSmart(8) returns 0
I have tried the following code to
import java.util.Arrays;
public class IsSmart {
public static void main(String[] args) {
// TODO Auto-generated method stub
int x = isSmart(11);
System.out.println(x);
}
public static int isSmart(int n) {
int[] y = new int[n];
int j = 0;
for (int i = 1; i <= n; i++) {
y[j] = i;
j++;
}
System.out.println(Arrays.toString(y));
for (int i = 0; i <= y.length; i++) {
int diff = 0;
y[j] = y[i+1] - y[i] ;
y[i] = diff;
}
System.out.println(Arrays.toString(y));
for (int i = 0; i < y.length; i++) {
if(n == y[i])
return 1;
}
return 0;
}
}
When I test it with 11 it is giving me 0 but it shouldn't. Any idea how to correct my mistakes?
It can be done in a simpler way as follows
import java.util.Arrays;
public class IsSmart {
public static void main(String[] args) {
int x = isSmart(11);
System.out.println("Ans: "+x);
}
public static int isSmart(int n) {
//------------ CHECK THIS LOGIC ------------//
int[] y = new int[n];
int diff = 1;
for (int i = 1; i < n; i++) {
y[0] =1;
y[i] = diff + y[i-1];
diff++;
}
//------------ CHECK THIS LOGIC ------------//
System.out.println(Arrays.toString(y));
for (int i = 0; i < y.length; i++) {
if(n == y[i])
return 1;
}
return 0;
}
}
One of the problems is the way that your populating your array.
The array can be populated as such
for(int i = 0; i < n; i++) {
y[i] = (i == 0) ? 1 : y[i - 1] + i;
}
The overall application of the function isSmart can be simplified to:
public static int isSmart(int n) {
int[] array = new int[n];
for(int i = 0; i < n; i++) {
array[i] = (i == 0) ? 1 : array[i - 1] + i;
}
for (int i = 0; i < array.length; i++) {
if (array[i] == n) return 1;
}
return 0;
}
Note that you don't need to build an array:
public static int isSmart(int n) {
int smart = 1;
for (int i = 1; smart < n; i++) {
smart = smart + i;
}
return smart == n ? 1 : 0;
}
Here is a naive way to think of it to get you started - you need to fill out the while() loop. The important thing to notice is that:
The next value of the sequence will be the number of items in the sequence + the last item in the sequence.
import java.util.ArrayList;
public class Test {
public static void main(String[] args) {
System.out.println(isSmart(11));
}
public static int isSmart(int n) {
ArrayList<Integer> sequence = new ArrayList<Integer>();
// Start with 1 in the ArrayList
sequence.add(1);
// You need to keep track of the index, as well as
// the next value you're going to add to your list
int index = 1; // or number of elements in the sequence
int nextVal = 1;
while (nextVal < n) {
// Three things need to happen in here:
// 1) set nextVal equal to the sum of the current index + the value at the *previous* index
// 2) add nextVal to the ArrayList
// 3) incriment index by 1
}
// Now you can check to see if your ArrayList contains n (is Smart)
if (sequence.contains(n)) { return 1; }
return 0;
}
}
First think of a mathematical solution.
Smart numbers form a sequence:
a0 = 1
an+1 = n + an
This gives a function for smart numbers:
f(x) = ax² + bx + c
f(x + 1) = f(x) + x = ...
So the problem is to find for a given y a matching x.
You can do this by a binary search.
int isSmart(int n) {
int xlow = 1;
int xhigh = n; // Exclusive. For n == 0 return 1.
while (xlow < xhigh) {
int x = (xlow + xhigh)/2;
int y = f(x);
if (y == n) {
return 1;
}
if (y < n) {
xlow = x + 1;
} else {
xhigh = x;
}
}
return 0;
}
Yet smarter would be to use the solution for x and look whether it is an integer:
ax² + bx + c' = 0 where c' = c - n
x = ...
I was playing around with this and I noticed something. The smart numbers are
1 2 4 7 11 16 22 29 ...
If you subtract one you get
0 1 3 6 10 15 21 28 ...
0 1 2 3 4 5 6 7 ...
The above sequence happens to be the sum of the first n numbers starting with 0 which is n*(n+1)/2. So add 1 to that and you get a smart number.
Since n and n+1 are next door to each other you can derive them by reversing the process.
Take 29, subtract 1 = 28, * 2 = 56. The sqrt(56) rounded up is 8. So the 8th smart number (counting from 0) is 29.
Using that information you can detect a smart number without a loop by simply reversing the process.
public static int isSmart(int v) {
int vv = (v-1)*2;
int sq = (int)Math.sqrt(vv);
int chk = (sq*(sq+1))/2 + 1;
return (chk == v) ? 1 : 0;
}
Using a version which supports longs have verified this against the iterative process from 1 to 10,000,000,000.
My current assignment is on recursion, which is why I have't used for loops here.
Basically I want to return the final determinant of an array. I can get the answer that I am looking for, but even though I have a return statement there, for some reason the program continues to loop through one more time.
My output looks like this:
j1: 0
j1: 2
j3: 0
n3: 2
j4: 0
n4: 2
j5: 1
j5: 2
j1: 1
j1: 2
j3: 1
n3: 2
j4: 1
n4: 2
j5: 2
j5: 2
j1: 2
j1: 2
Final Det2: 3
j2: 2
n2: 2
j6: 2
n6: 2
j6: 1
n6: 2
Returned value: 18
which basically means that my j value changes back from 2 to 1 somehow?
public class Lab2 {
public static void main(String[] args) {
int[][] inputArray = new int[][]{{2, 3},{5,9}};
int[][] initialArray = new int[][]{{2, 3},{5,9}};
int j = 0;
int n = inputArray.length;
int finalDet = 0;
System.out.println("Returned value: " + determinant(inputArray, j, initialArray, finalDet, n));
}
//power function works!
public static int power(int i, int j){
int power = (int) Math.pow(-1, i+j);
return power;
}
public static int determinant(int[][] inputArray, int j, int[][]initialArray, int finalDet, int n){
inputArray = initialArray;
int minorLength = n;
int[][] detArray = new int[n-1][n-1];
int[][] detStep = new int[n][n];
int row = 1; //starts row for minor at 1 since top row is always deleted
int detColumn = 0; //index for columns start at 0
int inColumn = 0;
System.out.println("j1: "+j);
System.out.println("j1: "+n);
if(j == n){
System.out.println("Final Det2: "+ finalDet);
System.out.println("j2: "+j);
System.out.println("n2: "+n);
return finalDet;
}
if(n == 1){
return finalDet;
}
System.out.println("j3: "+j);
System.out.println("n3: "+n);
//this part does the det function summation
if (j<n){
//this part gets the minor until it is small enough to work with
if (minorLength>1){
detArray = minor(inputArray, detArray, row, 0, 0, j, minorLength);
System.out.println("j4: "+j);
System.out.println("n4: "+n);
inputArray = detArray;
minorLength = inputArray[0].length;
}
finalDet = finalDet + power(0,j)*inputArray[0][0]*initialArray[0][j];
j++;
System.out.println("j5: "+j);
System.out.println("j5: "+n);
determinant(inputArray, j, initialArray, finalDet, n);
}
System.out.println("j6: "+j);
System.out.println("n6: "+n);
return finalDet;
}
//minor function works!!!
//this would be so much easier to do iteratively!!!
public static int[][] minor(int[][] inputArray, int[][] detArray, int row, int detColumn, int inColumn, int j, int n){ //start row at 1, not 0
if (row < n){
if(inColumn < n){
if (inColumn == j){
minor(inputArray, detArray, row, detColumn, inColumn+1, j, n);
}
if (inColumn != j){
detArray[row-1][detColumn] = inputArray[row][inColumn];
minor(inputArray, detArray, row, detColumn+1, inColumn+1, j, n);
}
}
if (inColumn == n){
minor(inputArray, detArray, row+1, 0, 0, j, n);
}
}
/*for (int dispRow = 0; dispRow < detArray.length; dispRow++){
for (int dispCol = 0; dispCol < detArray.length; dispCol++){
System.out.print(detArray[dispRow][dispCol]);
}
System.out.println("");
} */
return detArray;
}
}
You are not returning anything when j == 1. I suspect that's where the problem might be.
Apparently the issue was:
determinant(inputArray, j, initialArray, finalDet, n);
setting it equal to the return variable stopped the extra looping gave me the correct output. Go figure!
finalDet= determinant(inputArray, j, initialArray, finalDet, n);
I'm given 2 integrals, the first is the number of segments (Xi,Xj) and the second is the number of points that can or cant be inside those segments.
As an example, the input could be:
2 3
0 5
8 10
1 6 11
Where, in first line, 2 means "2 segments" and 3 means "3 points".
The 2 segments are "0 to 5" and "8 to 10", and the points to look for are 1, 6, 11.
The output is
1 0 0
Where point 1 is in segment "0 to 5", and point 6 and 11 are not in any segment. If a point appears in more than one segment, like a 3, the output would be 2.
The original code, was just a double loop to search the points between segments. I used the Java Arrays quicksort (modified so when it sorts endpoints of segments, sorts also startpoints so start[i] and end[i] belong to the same segment i) to improve the speed of the double loop but it isnt enought.
The next code works fine but when there's too many segments it gets very slow:
public class PointsAndSegments {
private static int[] fastCountSegments(int[] starts, int[] ends, int[] points) {
sort(starts, ends);
int[] cnt2 = CountSegments(starts,ends,points);
return cnt2;
}
private static void dualPivotQuicksort(int[] a, int[] b, int left,int right, int div) {
int len = right - left;
if (len < 27) { // insertion sort for tiny array
for (int i = left + 1; i <= right; i++) {
for (int j = i; j > left && b[j] < b[j - 1]; j--) {
swap(a, b, j, j - 1);
}
}
return;
}
int third = len / div;
// "medians"
int m1 = left + third;
int m2 = right - third;
if (m1 <= left) {
m1 = left + 1;
}
if (m2 >= right) {
m2 = right - 1;
}
if (a[m1] < a[m2]) {
swap(a, b, m1, left);
swap(a, b, m2, right);
}
else {
swap(a, b, m1, right);
swap(a, b, m2, left);
}
// pivots
int pivot1 = b[left];
int pivot2 = b[right];
// pointers
int less = left + 1;
int great = right - 1;
// sorting
for (int k = less; k <= great; k++) {
if (b[k] < pivot1) {
swap(a, b, k, less++);
}
else if (b[k] > pivot2) {
while (k < great && b[great] > pivot2) {
great--;
}
swap(a, b, k, great--);
if (b[k] < pivot1) {
swap(a, b, k, less++);
}
}
}
// swaps
int dist = great - less;
if (dist < 13) {
div++;
}
swap(a, b, less - 1, left);
swap(a, b, great + 1, right);
// subarrays
dualPivotQuicksort(a, b, left, less - 2, div);
dualPivotQuicksort(a, b, great + 2, right, div);
// equal elements
if (dist > len - 13 && pivot1 != pivot2) {
for (int k = less; k <= great; k++) {
if (b[k] == pivot1) {
swap(a, b, k, less++);
}
else if (b[k] == pivot2) {
swap(a, b, k, great--);
if (b[k] == pivot1) {
swap(a, b, k, less++);
}
}
}
}
// subarray
if (pivot1 < pivot2) {
dualPivotQuicksort(a, b, less, great, div);
}
}
public static void sort(int[] a, int[] b) {
sort(a, b, 0, b.length);
}
public static void sort(int[] a, int[] b, int fromIndex, int toIndex) {
rangeCheck(a.length, fromIndex, toIndex);
dualPivotQuicksort(a, b, fromIndex, toIndex - 1, 3);
}
private static void rangeCheck(int length, int fromIndex, int toIndex) {
if (fromIndex > toIndex) {
throw new IllegalArgumentException("fromIndex > toIndex");
}
if (fromIndex < 0) {
throw new ArrayIndexOutOfBoundsException(fromIndex);
}
if (toIndex > length) {
throw new ArrayIndexOutOfBoundsException(toIndex);
}
}
private static void swap(int[] a, int[] b, int i, int j) {
int swap1 = a[i];
int swap2 = b[i];
a[i] = a[j];
b[i] = b[j];
a[j] = swap1;
b[j] = swap2;
}
private static int[] naiveCountSegments(int[] starts, int[] ends, int[] points) {
int[] cnt = new int[points.length];
for (int i = 0; i < points.length; i++) {
for (int j = 0; j < starts.length; j++) {
if (starts[j] <= points[i] && points[i] <= ends[j]) {
cnt[i]++;
}
}
}
return cnt;
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n, m;
n = scanner.nextInt();
m = scanner.nextInt();
int[] starts = new int[n];
int[] ends = new int[n];
int[] points = new int[m];
for (int i = 0; i < n; i++) {
starts[i] = scanner.nextInt();
ends[i] = scanner.nextInt();
}
for (int i = 0; i < m; i++) {
points[i] = scanner.nextInt();
}
//use fastCountSegments
int[] cnt = fastCountSegments(starts, ends, points);
for (int x : cnt) {
System.out.print(x + " ");
}
}
I believe the problem is in the CountSegments() method but I'm not sure of another way to solve it. Supposedly, I should use a divide and conquer algorithm, but after 4 days, I'm up to any solution.
I found a similar problem in CodeForces but the output is different and most solutions are in C++. Since I have just 3 months that I started to learn java, I think I have reached my knowledge limit.
Given the constrains by OP, let n be the # of segments, m be the number of points to be query, where n,m <= 5*10^4, I can come up with a O(nlg(n) + mlg(n)) solution (which should be enough to pass most online judge)
As each query is a verifying problem: Can the point be covered by some intervals, yes or no, we do not need to find which / how many intervals the point has been covered.
Outline of the algorithm:
Sort all intervals first by starting point, if tie then by length (rightmost ending point)
Try to merge the intervals to get some disjoint overlapping intervals. For e.g. (0,5), (2,9), (3,7), (3,5), (12,15) , you will get (0,9), (12,15). As the intervals are sorted, this can be done greedily in O(n)
Above are the precomputation, now for each point, we query using the disjoint intervals. Simply binary search if any interval contains such point, each query is O(lg(n)) and we got m points, so total O(m lg(n))
Combine whole algorithm, we will get an O(nlg(n) + mlg(n)) algorithm
This is an implementation similar to #Shole's idea:
public class SegmentsAlgorithm {
private PriorityQueue<int[]> remainSegments = new PriorityQueue<>((o0, o1) -> Integer.compare(o0[0], o1[0]));
private SegmentWeight[] arraySegments;
public void addSegment(int begin, int end) {
remainSegments.add(new int[]{begin, end});
}
public void prepareArrayCache() {
List<SegmentWeight> preCalculate = new ArrayList<>();
PriorityQueue<int[]> currentSegmentsByEnds = new PriorityQueue<>((o0, o1) -> Integer.compare(o0[1], o1[1]));
int begin = remainSegments.peek()[0];
while (!remainSegments.isEmpty() && remainSegments.peek()[0] == begin) {
currentSegmentsByEnds.add(remainSegments.poll());
}
preCalculate.add(new SegmentWeight(begin, currentSegmentsByEnds.size()));
int next;
while (!remainSegments.isEmpty()) {
if (currentSegmentsByEnds.isEmpty()) {
next = remainSegments.peek()[0];
} else {
next = Math.min(currentSegmentsByEnds.peek()[1], remainSegments.peek()[0]);
}
while (!currentSegmentsByEnds.isEmpty() && currentSegmentsByEnds.peek()[1] == next) {
currentSegmentsByEnds.poll();
}
while (!remainSegments.isEmpty() && remainSegments.peek()[0] == next) {
currentSegmentsByEnds.add(remainSegments.poll());
}
preCalculate.add(new SegmentWeight(next, currentSegmentsByEnds.size()));
}
while (!currentSegmentsByEnds.isEmpty()) {
next = currentSegmentsByEnds.peek()[1];
while (!currentSegmentsByEnds.isEmpty() && currentSegmentsByEnds.peek()[1] == next) {
currentSegmentsByEnds.poll();
}
preCalculate.add(new SegmentWeight(next, currentSegmentsByEnds.size()));
}
SegmentWeight[] arraySearch = new SegmentWeight[preCalculate.size()];
int i = 0;
for (SegmentWeight l : preCalculate) {
arraySearch[i++] = l;
}
this.arraySegments = arraySearch;
}
public int searchPoint(int p) {
int result = 0;
if (arraySegments != null && arraySegments.length > 0 && arraySegments[0].begin <= p) {
int index = Arrays.binarySearch(arraySegments, new SegmentWeight(p, 0), (o0, o1) -> Integer.compare(o0.begin, o1.begin));
if (index < 0){ // Bug fixed
index = - 2 - index;
}
if (index >= 0 && index < arraySegments.length) { // Protection added
result = arraySegments[index].weight;
}
}
return result;
}
public static void main(String[] args) {
SegmentsAlgorithm algorithm = new SegmentsAlgorithm();
int[][] segments = {{0, 5},{3, 10},{8, 9},{14, 20},{12, 28}};
for (int[] segment : segments) {
algorithm.addSegment(segment[0], segment[1]);
}
algorithm.prepareArrayCache();
int[] points = {-1, 2, 4, 6, 11, 28};
for (int point: points) {
System.out.println(point + ": " + algorithm.searchPoint(point));
}
}
public static class SegmentWeight {
int begin;
int weight;
public SegmentWeight(int begin, int weight) {
this.begin = begin;
this.weight = weight;
}
}
}
It prints:
-1: 0
2: 1
4: 2
6: 1
11: 2
28: 0
EDITED:
public static void main(String[] args) {
SegmentsAlgorithm algorithm = new SegmentsAlgorithm();
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int m = scanner.nextInt();
for (int i = 0; i < n; i++) {
algorithm.addSegment(scanner.nextInt(), scanner.nextInt());
}
algorithm.prepareArrayCache();
for (int i = 0; i < m; i++) {
System.out.print(algorithm.searchPoint(scanner.nextInt())+ " ");
}
System.out.println();
}
Given k rooks and a n by n chess board, the rooks can safely be placed on the board W different ways, where
W = k!(n C k)^2
written differently W = n!n!/(k!(n-k)!(n-k)!)
PROBLEM STATEMENT:
Write a program that will run over a n by n chessboard and count all the ways that k rooks can safely be placed on the board.
MY RESEARCH:
After searching the internet I finally find a nQueensSolution code on Geekviewpoint and I modify it as below. However my code only works when k = n. Does anyone have an idea how to solve this for k<n?
Here is my code:
static int kRooksPermutations(int[] Q, int col, int k, int kLimit) {
int count = 0;
for (int x = 0; x < Q.length && col < Q.length; x++)
if (safeToAdd(Q, x, col)) {
if (k == kLimit - 1) {
count++;
Q[col] = -1;
} else {
Q[col] = x;
count += kRooksPermutations(Q, col + 1, k + 1, kLimit);
}
}
return count;
}//
static boolean safeToAdd(int[] Q, int r, int c) {
for (int y = 0; y < c; y++)
if (Q[y] == r)
return false;
return true;
}//
Here is a test code
public static void main(String... strings) {
kRooksPermutations(8,5);
}
Got it!
// Empty
static final int MT = -1;
static int kRooksPermutations(int[] Q, int col, int rooksInHand) {
// Are we at the last col?
if (col >= Q.length) {
// If we've placed K rooks then its a good'n.
return rooksInHand == 0 ? 1 : 0;
}
// Count at this level starts at 0
int count = 0;
// Have we run out of rooks?
if (rooksInHand > 0) {
// No! Try putting one in each row in this column.
for (int row = 0; row < Q.length; row++) {
// Can a rook be placed here?
if (safeToAdd(Q, row, col)) {
// Mark this spot occupied.
Q[col] = row;
// Recurse to the next column with one less rook.
count += kRooksPermutations(Q, col + 1, rooksInHand - 1);
// No longer occupied.
Q[col] = MT;
}
}
}
// Also try NOT putting a rook in this column.
count += kRooksPermutations(Q, col + 1, rooksInHand);
return count;
}
static boolean safeToAdd(int[] Q, int row, int col) {
// Unoccupied!
if (Q[col] != MT) {
return false;
}
// Do any columns have a rook in this row?
// Could probably stop at col here rather than Q.length
for (int c = 0; c < Q.length; c++) {
if (Q[c] == row) {
// Yes!
return false;
}
}
// All clear.
return true;
}
// Main entry - Build the array and start it all going.
private static void kRooksPermutations(int N, int K) {
// One for each column of the board.
// Contains the row number in which a rook is placed or -1 (MT) if the column is empty.
final int[] Q = new int[N];
// Start all empty.
Arrays.fill(Q, MT);
// Start at column 0 with no rooks placed.
int perms = kRooksPermutations(Q, 0, K);
// Print it.
System.out.println("Perms for N = " + N + " K = " + K + " = " + perms);
}
public static void main(String[] args) {
kRooksPermutations(8, 1);
kRooksPermutations(8, 2);
kRooksPermutations(8, 3);
kRooksPermutations(8, 4);
kRooksPermutations(8, 5);
kRooksPermutations(8, 6);
kRooksPermutations(8, 7);
kRooksPermutations(8, 8);
}
Prints:
Perms for N = 8 K = 1 = 64
Perms for N = 8 K = 2 = 1568
Perms for N = 8 K = 3 = 18816
Perms for N = 8 K = 4 = 117600
Perms for N = 8 K = 5 = 376320
Perms for N = 8 K = 6 = 564480
Perms for N = 8 K = 7 = 322560
Perms for N = 8 K = 8 = 40320
I'd probably solve the problem a different way:
solutions = 0;
k = number_of_rooks;
recurse(0,k);
print solutions;
...
recurse(row, numberOfRooks) {
if (numberOfRooks == 0) {
++solution;
return;
}
for(i=row; i<n; i++) {
for(j=0; j<n; j++) {
if (rook_is_ok_at(i, j)) {
place rook at i, j
recurse(i+1, numberOfRooks-1)
remove rook from i, j
}
}
}
}
This solves the problem in the general case. 8 rooks, 5 rooks, doesn't matter. Because all the rooks are unique, note when we place a rook we don't have to start over at (0,0)
Edit here are some results:
Here's are results I get for 1 to 8 rooks:
For 1 rooks, there are 64 unique positions
For 2 rooks, there are 1568 unique positions
For 3 rooks, there are 18816 unique positions
For 4 rooks, there are 117600 unique positions
For 5 rooks, there are 376320 unique positions
For 6 rooks, there are 564480 unique positions
For 7 rooks, there are 322560 unique positions
For 8 rooks, there are 40320 unique positions