I am writing the code for peak finding algorithm for a 1D array. I have read this post Peak finding algorithm. This is exactly what I am trying to do, there is discussion about time complexity but nothing of sort of pseudocode. The problem:
Given an array [a,b,c,d,e,f,g] where a to g are numbers, b is a peak if and only if a<=b and b>=c.
Example: given an array {1,2,3,4,5,19,25,20}, index 6 should be returned.
The edge cases should give:
{100,4,3,1,19,20} -- index 0
{1,3,5,19,20} -- index 4
I have implemented in Java. my current run-time is O(n). I am wondering if this could be improved
public static int naive(int[] arr){
int l=arr.length;
if (arr[0]>=arr[1]) {
return 0;
}
if (arr[l-1]>arr[l-2]){
return l-1;
}
for (int i=1; i < arr.length-1;i++){
if (arr[i] >= arr[i-1] && arr[i] >= arr[i+1] ){
return i;
}
}
return -1;
}
The following function is probably a tiny bit more efficient than yours. Note that this will find a local maximum.
public static int findLocalMaximum(int[] arr){
int i = 0;
while(i + 1 < arr.length && arr[i+1] >= arr[i]) {
++i;
}
return i;
}
Edit: The following function finds peaks as defined in the question. Note that I removed the boundary check in the while loop, as the loop will only be reached if arr[l-2] > arr[l-1], an so the condition in the while loop will be false and l-2 will be returned.
public static int findPeak(int[] arr){
int l = arr.length;
if(arr[0] >= arr[1]) {
return 0;
}
if(arr[l-1] >= arr[l-2]) {
return l-1;
}
int i = 1;
while(arr[i+1] > arr[i]) {
++i;
}
return i;
}
If I may propose my solution:
public static int findPeak(int[] array, int start, int end) {
int index = start + (end - start) / 2;
if (index - 1 >= 0 && array[index] < array[index - 1]) {
return findPeak(array, start, index - 1);
} else if (index + 1 <= array.length - 1 && array[index] < array[index + 1]) {
return findPeak(array, index + 1, end);
} else {
return array[index];
}
}
I think it is simpler to handle edge cases directly in the if statements. I also tested with a couple of inputs and it seems to work.
A binary search-like algorithm should work. That employs divide and conquer strategy. since you are interested in single peak, the best you can do is O(log n). But if you want to find all peaks, it will be O(n) atleast.
Here is the divide-and conquer algorithm:
public static int peak1D(int[] arr, int start, int end){
//edge cases
if (end-start==1){
if (start==0)
return start;
else
return end;
}
int i = start+end>>>1;
if (arr[i]<arr[i-1])
return peak1D(arr,start,i);
if (arr[i]<arr[i+1]){
return peak1D(arr, i, end);
}
else
return i;
}
I tested with a couple of inputs and it seems to work. my handling of edge cases is not great. though it is simple reasoning
Assume Array is global for simplicity you can pass it if you want.
private static int getPeak1D(int start,int end)
{
int x = (start+end)/2;
if( (x == 0 && array[x] >= array[x+1]) ||
(x == array.length-1 && array[x]>=array[x-1]) ||
(x>0 && x< array.length-1 && array[x] >= array[x-1] && array[x] >= array[x+1]))
return x;
if(x+1 < array.length && array[x] < array[x+1])
temp = getPeak1D(x+1,end);
if(temp > -1)
return temp;
if(x-1 > -1 && array[x] < array[x-1])
return getPeak1D(0,x-1);
else
return -1;
}
The First if check first edge, second edge, and inner part for peaks.
if no peaks are found, if array[x+1] > array[x], The Second if will go to the right half of the array. we store it in temp (i have it as global) we dont return it because in case both array[x+1] and array[x-1] are both bigger than array[x] but the right side didn't find any peaks you should go to the third if to check the left side
Check this for the logic behind it
https://courses.csail.mit.edu/6.006/spring11/rec/rec02.pdf
Related
I'm trying to solve the staircase problem in java with a method that gets the number of stairs (n) and the maximum step size (maxStep). Somehow it works until step size is > 3 after that I get a Stackoverflow error but I don't know why that is.
public static int climbStairs(int n, int maxStep) {
if (n == 0 || n == 1) {
return 1;
} else if (n == 2) {
return 2;
} else {
int count = 0;
for (int i = 1; i <= maxStep; i++) {
count += climbStairs(n - i, maxStep);
}
return count;
}
}
Try this code hope it will work.
public static int climbStairs2(int n, int maxStep) {
if (n == 0 || n == 1) {
return 1;
} else if (n < maxStep) {
return n;
} else {
int count = 0;
for (int i = 1; i <= maxStep; i++) {
count += climbStairs2(n - i, maxStep);
}
return count;
}
}
You don't check whether the maxstep is smaller than the step count. This means that after a while, the i<=maxstep can be > n, which results in negative n for the next recursion. If it once turns to the negatives, it will recurse infinitely. To fix it, just check for n<=maxstep or n<=0.
Example of your 'bad' code: Try inputs 5,4: it will start the method with n=
5
4
3
-1
-2
Trying to solve codility lessons for practice and working on this.
Written my code in Java and tested the code on a wide range of inputs, however the code fails for extreme_min_max, single and double in the codility test results.
Assumption given:
N is an integer within the range [1..100,000].
Each element of array A is an integer within the range [1..1,000,000,000].
Explanation of my code:
1. Sort the given array.
2. Iterate over each element in the array to find the difference between every consecutive pair. If the difference is not 1, Then its not a perm hence return 0. In case there is only one element in the array, return 1.
Can anyone please help me find out the bug(s) in my code?
My code:
public int solution(int[] A)
{
if(A.length == 1)
return 1;
Arrays.sort(A);
for (int i = 0; i < A.length-1; i++)
{
long diff = Math.abs(A[i] - A[i+1]);
if(diff!=1)
return 0;
}
return 1;
}
Here is simple and better implementation which runs in O(N) time complexity and takes O(N) space complexity.
public int solution(int[] A)
{
int size = A.length;
int hashArray[] = new int[size+1];
for (int i = 0; i < size; i++)
{
if(A[i]>size)
return 0;
else
hashArray[A[i]]+=1;
}
for(int i=1;i<=size;i++)
if(hashArray[i]!=1)
return 0;
return 1;
}
Try this in C# (Score 100%) :
using System;
using System.Linq;
class Solution {
public int solution(int[] A) {
if (A.Any(x => x == 0)) { return 0; }
var orderSelect = A.OrderBy(x => x).GroupBy(x => x);
if (orderSelect.Any(x => x.Count() > 1)) { return 0; }
var res = Enumerable.Range(1, A.Length).Except(A);
return res.Any() ? 0 : 1;
}
}
Pretty simple:
Your code doesn't check this condition:
A permutation is a sequence containing each element from 1 to N once, and only once.
Ensure that the first element after sorting is 1, and everything should work.
I'm not big on Java syntax, but what you want to do here is:
Create an array temp the length of A - initialized to 0.
Go over A and do temp[A[i]]++.
Go over temp, and if any place in the array is not 1, return false.
If duplicate exists - return 0 I have implemented with 100% pass
https://codility.com/demo/results/trainingWX2E92-ASF/
public static int permCheck(int A[]){
Set<Integer> bucket = new HashSet<Integer>();
int max = 0;
int sum=0;
for(int counter=0; counter<A.length; counter++){
if(max<A[counter]) max=A[counter];
if(bucket.add(A[counter])){
sum=sum+A[counter];
}
else{
return 0;
}
}
System.out.println(max+"->"+sum);
int expectedSum = (max*(max+1))/2;
if(expectedSum==sum)return 1;
return 0;
}
Here's my first 100% code.
I can't say if it's the fastest but it seems all correct -- watch the double OR ( || ) condition.
import java.util.Arrays;
class Solution
{
public int solution(int[] A)
{
int i = 0;
int size = A.length;
if ( size > 0 && size < 100001)
{
// Sort the array ascending:
Arrays.sort(A);
// Check each element:
for(i = 0; i < size; i++)
if ( A[i] > size || A[i] != (i + 1) )
return 0;
return 1;
}
return 0;
}
}
EDIT
Actually, we need not worry about valid first element data (i.e. A[i] > 0) because, after sorting, a valid perm array must have A[0] = 1 and this is already covered by the condition A[i] = i + 1.
The upper limit for array entries (> 1,000,000,000) is restricted further by the limit on the array size itself (100,000) and we must check for conformity here as there will be a Codility test for this. So I have removed the lower limit condition on array entries.
Below code runs and gave me a 100%, the time complexity is O(n):
private static int solution(int[] A) {
int isPermutation = 1; // all permutations start at 1
int n = A.length;
Arrays.sort(A);
if (n == 0) return 0; // takes care of edge case where an empty array is passed
for (int i = 0; i < n; i++) {
if (A[i] != isPermutation) { //if current array item is not equals to permutation, return 0;
return 0;
}
isPermutation++;
}
return 1;
}
100% score with complexity O(N)
public int solution(int[] A) {
int res = 1;
if (A.length == 1 && A[0]!=1)
return 0;
int[] B = new int[A.length];
for (int j : A) {
int p = j - 1;
if (A.length > p)
B[p] = j;
}
for (int i = 0; i < B.length - 1; i++) {
if (B[i] + 1 != B[i + 1]) {
res = 0;
break;
}
}
return res;
}
I'm a programming student and rather than post the whole assignment I'll just ask for help solving what I've tried for hours now to understand. I'm tasked with sorting an array of strings using the quicksort method. Everything else I've been tasked with as part of this problem is fine but when I tested the sorting method by printing out the String Array, it's completely jumbled up without any seeming rhyme or reason. Please help me pinpoint the error in my code, or the several glaring errors I've overlooked. The array of strings provided is this list of 65 names: http://pastebin.com/jRrgeV1E and the method's code is below:
private static void quickSort(String[] a, int start, int end)
{
// index for the "left-to-right scan"
int i = start;
// index for the "right-to-left scan"
int j = end;
// only examine arrays of 2 or more elements.
if (j - i >= 1)
{
// The pivot point of the sort method is arbitrarily set to the first element int the array.
String pivot = a[i];
// only scan between the two indexes, until they meet.
while (j > i)
{
// from the left, if the current element is lexicographically less than the (original)
// first element in the String array, move on. Stop advancing the counter when we reach
// the right or an element that is lexicographically greater than the pivot String.
while (a[i].compareTo(pivot) < 0 && i <= end && j > i){
i++;
}
// from the right, if the current element is lexicographically greater than the (original)
// first element in the String array, move on. Stop advancing the counter when we reach
// the left or an element that is lexicographically less than the pivot String.
while (a[j].compareTo(pivot) > 0 && j >= start && j >= i){
j--;
}
// check the two elements in the center, the last comparison before the scans cross.
if (j > i)
swap(a, i, j);
}
// At this point, the two scans have crossed each other in the center of the array and stop.
// The left partition and right partition contain the right groups of numbers but are not
// sorted themselves. The following recursive code sorts the left and right partitions.
// Swap the pivot point with the last element of the left partition.
swap(a, start, j);
// sort left partition
quickSort(a, start, j - 1);
// sort right partition
quickSort(a, j + 1, end);
}
}
/**
* This method facilitates the quickSort method's need to swap two elements, Towers of Hanoi style.
*/
private static void swap(String[] a, int i, int j)
{
String temp = a[i];
a[i] = a[j];
a[j] = temp;
}
Ok, i was mistaken that it would work and found your tiny mistake.
Take a look at wikipedias pseudo code
You will notice that your conditions in the while loop are causing the error
if you change (a[i].compareTo(pivot) < 0 && i <= end && j > i) and (a[j].compareTo(pivot) > 0 && j >= start && j >= i) to
(a[i].compareTo(pivot) <= 0 && i < end && j > i) and (a[j].compareTo(pivot) >= 0 && j > start && j >= i).
Thought this would help for those who seek for a string sorting algorithm based on quick sorting method.
public class StringQuickSort {
String names[];
int length;
public static void main(String[] args) {
StringQuickSort sorter = new StringQuickSort();
String words[] = {"zz", "aa", "cc", "hh", "bb", "ee", "ll"}; // the strings need to be sorted are put inside this array
sorter.sort(words);
for (String i : words) {
System.out.print(i);
System.out.print(" ");
}
}
void sort(String array[]) {
if (array == null || array.length == 0) {
return;
}
this.names = array;
this.length = array.length;
quickSort(0, length - 1);
}
void quickSort(int lowerIndex, int higherIndex) {
int i = lowerIndex;
int j = higherIndex;
String pivot = this.names[lowerIndex + (higherIndex - lowerIndex) / 2];
while (i <= j) {
while (this.names[i].compareToIgnoreCase(pivot) < 0) {
i++;
}
while (this.names[j].compareToIgnoreCase(pivot) > 0) {
j--;
}
if (i <= j) {
exchangeNames(i, j);
i++;
j--;
}
}
//call quickSort recursively
if (lowerIndex < j) {
quickSort(lowerIndex, j);
}
if (i < higherIndex) {
quickSort(i, higherIndex);
}
}
void exchangeNames(int i, int j) {
String temp = this.names[i];
this.names[i] = this.names[j];
this.names[j] = temp;
}
}
I have given this a lot of thought and was unable to find the most optimal solution. I am preparing for technical interviews, but I haven't found very much stuff related to this question. My first step was to implement a naive O(n) algorithm that searches through the entire array to find the maximum integer. Now I know I can do much better than this, so I thought maybe there was a way to use Binary Search or take advantage of the fact that at least one half of the array is fully sorted. Maybe you could find the middle value and compare it to the start and end of the array.
Example:
[5, 7, 11, 1, 3] would return 11.
[7, 9, 15, 1, 3] would return 15.
In a sorted array (even rotated), you can be sure to use binary search (O(log2(n)).
/**
* Time complexity: O(log2(n))
* Space complexity: O(1)
*
* #param nums
* #return
*/
public int findMax(int[] nums) {
// binary search
int left = 0;
int right = nums.length - 1;
while (left < right) {
int mid = left + (right - left) / 2;
if (nums[left] < nums[mid]) {
left = mid;
} else if (nums[left] > nums[mid]) {
right = mid - 1;
} else {
// subtility here if there are duplicate elements in the array.
// shift the left linearly
left = left + 1;
}
}
return nums[left];
}
You have to binary search in a clever way to achieve a O(lg n) bound. Observe that the element to the right of the max element is the min (or none if the array is not rotated at all). So do a regular binary search but check that the element at index mid is the max, if not compare the first and last elements in each of the left/right subarrays. If first<last in the left subarray, you know that the left subarray is sorted and go right, otherwise you go left.
Let's assume that array is called a and it has n elements.
/* check if not rotated at all */
int ans = INFINITY;
if(a[0] < a[n-1] || n == 1)
{ ans = a[n-1];
return;
}
/* array is certainly rotated */
int l = 0, r = n-1;
while(r - l > 5)
{ int m = (l + r) / 2;
if(a[m] > a[m+1]) { ans = a[m]; break; }
else
{ if(a[l] < a[m-1]) l = m+1;
else r = m-1;
}
}
/* check the remaining elements (at most 5) in a loop */
if(ans == INFINITY)
{ for(int i = l; i <= r; i++)
{ ans = max(ans, a[i]);
}
}
I've not tested this code. The reason i break when the number of elements is 5 or less is to be sure that number of elements in either subarray is at least 2 (so you can be sure that first and last are not the same element). You've got to try this yourself and fix it if there is anything to fix. Hope this helps.
Use modified binary search to eliminate half the sorted subarray (if there are two sorted subarrays remove the "lower" subarray) in each step while keeping track of a potentially updated maximum.
#include <iostream>
#include <cstdlib>
#include <vector>
int main(int argc, char** argv)
{
std::vector<int> nums;
for(int i = 1; i < argc; i++)
nums.push_back(atoi(argv[i]));
int start = 0;
int end = argc - 2;
int max = nums[start];
while(start <= end) {
int mid = (start + end) >> 1;
int cand;
if(nums[start] <= nums[mid]) {
start = mid + 1;
} else {
end = mid - 1;
}
cand = nums[mid];
if(cand > max)
max = cand;
}
std::cout << max << std::endl;
return 0;
}
Question : find largest in the rotated sorted array.The array don't have any duplicates:
Solution : Using Binary Search.
The Idea : Always remember in a Sorted Rotated Array, the largest element will always be on the left side of the array. Similarly, the smallest element will always be on the right side of the array.
The code is :
public class Test19 {
public static void main(String[] args) {
int[] a = { 5, 6, 1, 2, 3, 4 };
System.out.println(findLargestElement(a));
}
private static int findLargestElement(int[] a) {
int start = 0;
int last = a.length - 1;
while (start + 1 < last) {
int mid = (last - start) / 2 + start;
if (mid < start) {
mid = start;
}
if (mid > start) {
last = mid - 1;
} else {
mid--;
}
} // while
if (a[start] > a[last]) {
return a[start];
} else
return a[last];
}
}
The solution I've come up with is both compact and efficient.
It is basically a spin-off of the Binary Search Algorithm.
int maxFinder(int[] array, int start, int end)
{
//Compute the middle element
int mid = (start + end) / 2;
//return the first element if it's a single element array
//OR
//the boundary pair has been discovered.
if(array.length == 1 || array[mid] > array[mid + 1])
{return mid;}
//Basic Binary Search implementation
if(array[mid] < array[start])
{return maxFinder(array, start, mid - 1);}
else if(array[mid] > array[end])
{return maxFinder(array, mid + 1, end);}
//Return the last element if the array hasn't been rotated at all.
else
{return end;}
}
Speaking of using binary search to solve this problem at a time complexity of O(log2n). I would do as the following
#include<stdio.h>
#define ARRSIZE 200
int greatestElement(int* , int ) ;
int main() {
int arr[ARRSIZE] ;
int n ;
printf("Enter the number of elements you want to enter in the array!") ;
scanf("%d" , &n) ;
printf("Enter the array elements\n") ;
for(int i = 0 ; i < n ; i++) {
scanf("%d", &arr[i]) ;
}
printf("%d is the maximum element of the given array\n",greatestElement(arr,n)) ;
}
int greatestElement(int* arr, int n) {
int mid = 0 ;
int start = 0 , end = n-1 ;
while(start < end) {
mid = (start+end)/2 ;
if(mid < n-1 && arr[mid] >= arr[mid+1]) {
return arr[mid] ;
}
if(arr[start] > arr[mid]) {
end = mid - 1 ;
}
else {
start = mid + 1;
}
}
return arr[start] ;
}```
This question is so easy with another version of binary search:
int solve(vector<int>& a) {
int n = a.size();
int k=0;
for(int b=n/2; b>=1; b/=2)
{
while(k+b<n && a[k+b] >= a[0])
k += b;
}
return a[k];
}
I have the following questions regarding my implementation of the code for the QuickSort Algorithm using the first element as the pivot always.
I have 2 sample files for my work and it seems that it does not work when given certain input. There appears to be a StackOverflowError on my recursion.
Is there something wrong with my code? Or is there something I'm missing out?
Input that work will be random integers x10000.
Input that will have error will be number 10000 - 1 in a decreasing manner.
Both inputs are via text files seperated by \n.
public void quickSortOne(Integer [] arr)
{
int first = 0;
int last = arr.length-1;
quickSort1(arr, first, last);
}
public void quickSort1(Integer [] arr, int first, int last)
{
if (arr == null || arr.length == 0)
return;
if (first >= last)
return;
//pick the pivot as first
//int middle = first + (last - first) / 2;
int pivot = arr[first];
//make left < pivot and right > pivot
int i = first, j = last;
while (i <= j) {
while (arr[i] < pivot) {
i++;
q1Comparison++;
}
while (arr[j] > pivot) {
j--;
q1Comparison++;
}
if (i <= j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
i++;
j--;
q1DataMove++;
}
}
//recursively sort two sub parts
if (first < j)
quickSort1(arr, first, j);
if (last > i)
quickSort1(arr, i, last);
}
You are running out of thread stack size due to default limit set by its OS. Especially for windows its very less (64KB).
Try running your app using below setting ->
java -Xss:512k myApp
You may also increase it to 1M or higher if needed. Here is the link to more info. Search for "Xss" on this page. ->
http://docs.oracle.com/cd/E13150_01/jrockit_jvm/jrockit/jrdocs/refman/optionX.html
Hope this helps!