Related
I have been studying algorithms recently, and got to the randomized select algorithm. Im trying to figure it out, and stumbled upon this website
https://www.geeksforgeeks.org/kth-smallestlargest-element-unsorted-array-set-2-expected-linear-time/
Which shows a code, with little to no explanation of how it works.
It works to find the kth smallest element, but how could it be changed in order to show the kth largest element?
Particularly on this method
int kthSmallest(int arr[], int l, int r, int k)
{
// If k is smaller than number of elements in array
if (k > 0 && k <= r - l + 1)
{
// Partition the array around a random element and
// get position of pivot element in sorted array
int pos = randomPartition(arr, l, r);
// If position is same as k
if (pos-l == k-1)
return arr[pos];
// If position is more, recur for left subarray
if (pos-l > k-1)
return kthSmallest(arr, l, pos-1, k);
// Else recur for right subarray
return kthSmallest(arr, pos+1, r, k-pos+l-1);
}
// If k is more than number of elements in array
return Integer.MAX_VALUE;
}
You don't have to modify this method kthSmallest. Instead you should modify method partition (taken from the link you provided):
int partition(int arr[], int l, int r)
{
int x = arr[r], i = l;
for (int j = l; j <= r - 1; j++)
{
if (arr[j] >= x)
{
swap(arr, i, j);
i++;
}
}
swap(arr, i, r);
return i;
}
I changed here the if statement : if (arr[j] <= x) to if (arr[j] >= x)
I had a problem statement which requires passing 3 different numbers to a method and checking which 3 numbers satisfies a certain constraint.
Here is my code, but I wanted to know instead of creating nested loops, is there any more optimized way of checking which set of triplet satisfies a certain constraint. ?
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class Solution
{
static List l = new ArrayList();
static int geometricTrick(String s)
{
int count = 0;
for (int i = 0; i < s.length(); i++)
{
for (int j = 0; j < s.length(); j++)
{
for (int k = 0; k < s.length(); k++)
{
if (is1stConstraintTrue(s, i, j, k) && is2ndConstraintTrue(i, j, k))
{
l.add(new Triplet(i, j, k));
}
}
}
}
count = l.size();
return count;
}
static boolean is2ndConstraintTrue(int i, int j, int k)
{
boolean retVal = false;
double LHS = Math.pow((j + 1), 2);
double RHS = (i + 1) * (k + 1);
if (LHS == RHS)
retVal = true;
else
retVal = false;
return retVal;
}
static boolean is1stConstraintTrue(String s, int i, int j, int k)
{
boolean retVal = false;
char[] localChar = s.toCharArray();
if (localChar[i] == 'a' && localChar[j] == 'b' && localChar[k] == 'c')
{
retVal = true;
}
return retVal;
}
static class Triplet
{
public int i, j, k;
public Triplet(int i, int j, int k)
{
this.i= i;
this.j= j;
this.k= k;
}
}
public static void main(String[] args)
{
Scanner in = new Scanner(System.in);
int n = in.nextInt();
String s = in.next();
int result = geometricTrick(s);
System.out.println(result);
}
}
Here are some hints:
Computing the square by multiplication will be faster than using pow
String::toCharray() is expensive. It copies all characters into a new array. Each time you call it. Don't call it multiple times.
If the result is the number of triples, you don't need to build a list. You don't even need to create Triple instances. Just count them.
Nested loops are not inefficient, if you need to iterate all combinations.
To provide you a simple and "stupid" solution to not use those inner loops.
Let's use a Factory like an Iterator. This would "hide" the loop by using condition statement.
public class TripletFactory{
final int maxI, maxJ, maxK;
int i, j ,k;
public TripletFactory(int i, int j, int k){
this.maxI = i;
this.maxJ = j;
this.maxK = k;
}
public Triplet next(){
if(++k > maxK){
k = 0;
if(++j > maxJ){
j = 0;
if(++i > maxI){
return null;
}
}
}
return new Triplet(i,j,k);
}
}
That way, you just have to get a new Triple until a null instance in ONE loop
TripletFactory fact = new TripletFactory(2, 3 ,5);
Triplet t = null;
while((t = fact.next()) != null){
System.out.println(t);
}
//no more Triplet
And use it like you want.
Then, you will have to update your constraint method to take a Triplet and use the getters to check the instance.
That could be a method of Triplet to let it validate itself by the way.
Note :
I used the same notation as the Iterator because we could implement Iterator and Iterable to use a notation like :
for(Triplet t : factory){
...
}
The naive approach you presented has cubic time complexity (three nested for-loops). If you have many occurrences of 'a', 'b' and 'c' within your input, it may be worth wile to first determine the indices of all 'a''s, 'b''s and 'c''s and then check your second condition only over this set.
import java.util.ArrayList;
import java.util.List;
public class Main {
public static List<Integer> getAllOccurrences(String input, char of) {
List<Integer> occurrences = new ArrayList<Integer>();
char[] chars = input.toCharArray();
for (int idx = 0; idx < chars.length; ++idx) {
if (of == chars[idx]) {
occurrences.add(idx);
}
}
return (occurrences);
}
static List<Triplet> geometricTrick(String input){
List<Integer> allAs = getAllOccurrences(input, 'a');
List<Integer> allBs = getAllOccurrences(input, 'b');
List<Integer> allCs = getAllOccurrences(input, 'c');
List<Triplet> solutions = new ArrayList<Triplet>();
// reorder the loops, so that the c-loop is the innermost loop (see
// below why this is useful and how it is exploited).
for (int a : allAs) {
for (int c : allCs) {
// calculate lhs as soon as possible, no need to recalculate the
// same value multiple times
final int lhs = ((a + 1) * (c + 1));
for (int b : allBs) {
final int rhs = ((b + 1) * (b + 1));
if (lhs > rhs) {
continue;
}
/* else */ if (lhs == rhs) {
solutions.add(new Triplet(a, b, c));
}
// by construction, the b-values are in ascending or der.
// Thus if the rhs-value is larger or equal to the
// lhs-value, we can skip all other rhs-values. for this
// lhs-value.
// if (lhs <= rhs) {
break;
// }
}
}
}
return (solutions);
}
static class Triplet {
public final int i;
public final int j;
public final int k;
public Triplet(int i, int j, int k) {
this.i = i;
this.j = j;
this.k = k;
}
}
}
Searching all occurrences of one char within a given String takes O(n) (method getAllOccurrences(...)), calling it three times does not change the complexity (3 * n \in O(n)). Iterating through all possible combinations of a, b and c takes #a * #b * #c time, where #a, #b and #c stay for the count of a's, b's and c's in your input. This gives a total time complexity of O(n + #a * #b * #c).
Note that the worst case time complexity, i.e. if 1/3 of your string consists of a's, 1/3 consists of b's and 1/3 consists of c's, is still cubic.
What's the simplest way to sort a primitive array in Java with a custom comparator (or key) function and without converting to an array of objects (for performance †).
† (Just a precaution, I'm not asking whether not converting to objects is a good decision from a performance POV.)
Sorting of an array of primitive values with a custom comparator is not supported by the standard Java libraries.
You could easily implement your a simple sort ( e.g. bubblesort - O(N^2) ) from scratch, but the problem is that for large enough arrays the saving you make by not converting to boxed types is lost in the less efficient sorting algorithm.
So your choices are:
Implement a high performance sort (mergesort, modified quicksort, etc) from scratch.
Find an existing high performance sort for primitive types that doesn't support comparators, and modify it.
See if you can find a suitable 3rd-party library that supports ptimitive arrays and comparators. (I haven't managed to find one ...)
(Note: the Comparator interface won't work here. It is not suitable for comparing primitive types.)
In Java 8 you can have your sort method take a function interface. This is modified code from OpenJDK (Copyright 1997-2007 Sun Microsystems, Inc. GPLv2):
import java.util.function.LongBinaryOperator;
public class ArraySort {
public static void sort(long[] x, LongBinaryOperator op) {
sort1(x, 0, x.length, op);
}
private static void sort1(long x[], int off, int len, LongBinaryOperator op) {
if (len < 7) {
for (int i=off; i<len+off; i++)
// Use custom comparator for insertion sort fallback
for (int j=i; j>off && (op.applyAsLong(x[j-1], x[j]) > 0); j--)
swap(x, j, j-1);
return;
}
int m = off + (len >> 1);
if (len > 7) {
int l = off;
int n = off + len - 1;
if (len > 40) {
int s = len/8;
l = med3(x, l, l+s, l+2*s);
m = med3(x, m-s, m, m+s);
n = med3(x, n-2*s, n-s, n);
}
m = med3(x, l, m, n);
}
long v = x[m];
int a = off, b = a, c = off + len - 1, d = c;
while(true) {
// Use custom comparator for checking elements
while (b <= c && (op.applyAsLong(x[b], v) <= 0)) {
if (x[b] == v)
swap(x, a++, b);
b++;
}
// Use custom comparator for checking elements
while (c >= b && (op.applyAsLong(x[c], v) >= 0)) {
if (x[c] == v)
swap(x, c, d--);
c--;
}
if (b > c)
break;
swap(x, b++, c--);
}
int s, n = off + len;
s = Math.min(a-off, b-a ); vecswap(x, off, b-s, s);
s = Math.min(d-c, n-d-1); vecswap(x, b, n-s, s);
if ((s = b-a) > 1)
sort1(x, off, s, op);
if ((s = d-c) > 1)
sort1(x, n-s, s, op);
}
private static void swap(long x[], int a, int b) {
long t = x[a];
x[a] = x[b];
x[b] = t;
}
private static void vecswap(long x[], int a, int b, int n) {
for (int i=0; i<n; i++, a++, b++)
swap(x, a, b);
}
private static int med3(long x[], int a, int b, int c) {
return (x[a] < x[b] ?
(x[b] < x[c] ? b : x[a] < x[c] ? c : a) :
(x[b] > x[c] ? b : x[a] > x[c] ? c : a));
}
}
And call it with lambdas or anything else implementing the LongBinaryOperator interface:
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
long x[] = {5, 5, 7, 1, 2, 5, 8, 9, 23, 5, 32, 45, 76};
ArraySort.sort(x, (a, b) -> b - a); // sort descending
System.out.println(Arrays.toString(x));
}
}
Output:
[76, 45, 32, 23, 9, 8, 7, 5, 5, 5, 5, 2, 1]
You can just build your own compare functions ,
and use one of the sort algorithms
easiest and slowest: BubbleSort ( O(N^2) ).
hardest but fastest : MergeSort( (O(Nlog(n) ) .
now in both algos you have the part that asks if A > B , in this part you should put your compare func.
boolean compare(int x, int y){
if(/* your crazy compare condition */)
return true;
else return false;
}
example in bubble sort :
procedure bubbleSort( A : list of sortable items )
repeat
swapped = false
for i = 1 to length(A) - 1 inclusive do:
/* if this pair is out of order */
if compare(A[i],A[i-1]) then // Notcie the compare instead of A[i] > A[i-1]
/* swap them and remember something changed */
swap( A[i-1], A[i] )
swapped = true
end if
end for
until not swapped
end procedure
hope this helps
Create a list of Integer representing the indexes in the array, sort the list. You can reuse the list of indexes many times for many sorts.
I copied the following from Java 6's Arrays.java and modified it to my needs. It uses insertion sort on smaller arrays so it should be faster than pure quicksort.
/**
* Sorts the specified sub-array of integers into ascending order.
*/
private static void sort1(int x[], int off, int len) {
// Insertion sort on smallest arrays
if (len < 7) {
for (int i=off; i<len+off; i++)
for (int j=i; j>off && x[j-1]>x[j]; j--)
swap(x, j, j-1);
return;
}
// Choose a partition element, v
int m = off + (len >> 1); // Small arrays, middle element
if (len > 7) {
int l = off;
int n = off + len - 1;
if (len > 40) { // Big arrays, pseudomedian of 9
int s = len/8;
l = med3(x, l, l+s, l+2*s);
m = med3(x, m-s, m, m+s);
n = med3(x, n-2*s, n-s, n);
}
m = med3(x, l, m, n); // Mid-size, med of 3
}
int v = x[m];
// Establish Invariant: v* (<v)* (>v)* v*
int a = off, b = a, c = off + len - 1, d = c;
while(true) {
while (b <= c && x[b] <= v) {
if (x[b] == v)
swap(x, a++, b);
b++;
}
while (c >= b && x[c] >= v) {
if (x[c] == v)
swap(x, c, d--);
c--;
}
if (b > c)
break;
swap(x, b++, c--);
}
// Swap partition elements back to middle
int s, n = off + len;
s = Math.min(a-off, b-a ); vecswap(x, off, b-s, s);
s = Math.min(d-c, n-d-1); vecswap(x, b, n-s, s);
// Recursively sort non-partition-elements
if ((s = b-a) > 1)
sort1(x, off, s);
if ((s = d-c) > 1)
sort1(x, n-s, s);
}
/**
* Swaps x[a] with x[b].
*/
private static void swap(int x[], int a, int b) {
int t = x[a];
x[a] = x[b];
x[b] = t;
}
/**
* Swaps x[a .. (a+n-1)] with x[b .. (b+n-1)].
*/
private static void vecswap(int x[], int a, int b, int n) {
for (int i=0; i<n; i++, a++, b++)
swap(x, a, b);
}
/**
* Returns the index of the median of the three indexed integers.
*/
private static int med3(int x[], int a, int b, int c) {
return (x[a] < x[b] ?
(x[b] < x[c] ? b : x[a] < x[c] ? c : a) :
(x[b] > x[c] ? b : x[a] > x[c] ? c : a));
}
I am writing a specific variant of quicksort class. However; the directions on this variant of quick sort is confusing me. I have written the code for quick sort, but I do not understand the description. Can anyone help me understand this description means for the variant so I can finalize it?
Description: implement a variant of quicksort with pivots chosen according to pivot_pos. That is, whenever the quicksort makes a recursive call to quicksort a subarray (A, p, r), it chooses as the pivot min(p+pivot,r).
To my interpretation, this is saying to include within the if statement of quicksort a int value of min(p + pivot, r). It would partition the array with the pivot representing this value, and quicksorting the array with this value as well.
public static int partition(int[] a, int p, int r)
{
int x = a[r];
int i = p - 1;
for( int j = p; j <= r - 1; j++)
{
if(a[j] <= x)
{
i++;
swap(a, i, j);
}
}
swap(a, i + 1, r);
return i + 1;
}
public static void quick_sort(int[] a, int p, int r)
{
if(p < r)
{
int q = partition(a, p, r);
quick_sort(a, p, q - 1);
quick_sort(a, q + 1, r);
}
}
I am trying to understand the 3-way radix Quicksort, and i dont understand why the the CUTOFF variable there? and the insertion method?
public class Quick3string {
private static final int CUTOFF = 15; // cutoff to insertion sort
// sort the array a[] of strings
public static void sort(String[] a) {
// StdRandom.shuffle(a);
sort(a, 0, a.length-1, 0);
assert isSorted(a);
}
// return the dth character of s, -1 if d = length of s
private static int charAt(String s, int d) {
assert d >= 0 && d <= s.length();
if (d == s.length()) return -1;
return s.charAt(d);
}
// 3-way string quicksort a[lo..hi] starting at dth character
private static void sort(String[] a, int lo, int hi, int d) {
// cutoff to insertion sort for small subarrays
if (hi <= lo + CUTOFF) {
insertion(a, lo, hi, d);
return;
}
int lt = lo, gt = hi;
int v = charAt(a[lo], d);
int i = lo + 1;
while (i <= gt) {
int t = charAt(a[i], d);
if (t < v) exch(a, lt++, i++);
else if (t > v) exch(a, i, gt--);
else i++;
}
// a[lo..lt-1] < v = a[lt..gt] < a[gt+1..hi].
sort(a, lo, lt-1, d);
if (v >= 0) sort(a, lt, gt, d+1);
sort(a, gt+1, hi, d);
}
// sort from a[lo] to a[hi], starting at the dth character
private static void insertion(String[] a, int lo, int hi, int d) {
for (int i = lo; i <= hi; i++)
for (int j = i; j > lo && less(a[j], a[j-1], d); j--)
exch(a, j, j-1);
}
// exchange a[i] and a[j]
private static void exch(String[] a, int i, int j) {
String temp = a[i];
a[i] = a[j];
a[j] = temp;
}
// is v less than w, starting at character d
private static boolean less(String v, String w, int d) {
assert v.substring(0, d).equals(w.substring(0, d));
return v.substring(d).compareTo(w.substring(d)) < 0;
}
// is the array sorted
private static boolean isSorted(String[] a) {
for (int i = 1; i < a.length; i++)
if (a[i].compareTo(a[i-1]) < 0) return false;
return true;
}
public static void main(String[] args) {
// read in the strings from standard input
String[] a = StdIn.readAll().split("\\s+");
int N = a.length;
// sort the strings
sort(a);
// print the results
for (int i = 0; i < N; i++)
StdOut.println(a[i]);
}
}
from http://www.cs.princeton.edu/algs4/51radix/Quick3string.java.html
It would appear to be used in order to invoke insertion sort for sufficiently small (size <= 15) arrays. This is most likely to speed up sorting.
It's a simple optimization of quicksort algorithm. The cost of recursive calls in quicksort are quite high, so for small arrays insertion sort works better. So, the idea is, that if length of subarray to be sorted os below certain threshold, it's better to sort it using insertion sort than quicksort. In your example, CUTOFF variable defines that threshold, i.e. if less than 15 elements are left, they are sorted using insertion sort instead of quicksort.
The sort method above is a recursive method. And every recursive method should have some kind of base case (otherwise it will keep calling itself, eventually leading to a stack overflow).
The insertion part is the base case in that method, because at every recursive step, the hi-lo difference keeps decreasing, & when its less than CUTOFF, the insertion sort will eventually be triggered, forcing the recursion to stop.
if (hi <= lo + CUTOFF) { // base case
insertion(a, lo, hi, d);
return;
}
Now, why insertion ? Because it works well for small arrays.
More on sorting here: http://www.sorting-algorithms.com/
This idea comes from Robert Sedgewick, who knows more about Quicksort than probably any man alive. It is cited in Donald E. Knuth, The Art of Computer Programming, Volume III, where he shows that for small M, insertion sort is faster than Quicksort, so he recommends not sorting small partitions < M at all and leaving it to one final insertion sort over the whole data set at the end. Knuth gives a function for calculating M (which is your CUTOFF), and which is 9 for his MIX pseudo-computer.