Majority element array Java O(nlogn) - java

The majority element in an array of size n is an element that appears more than n/2 times. I have to write a function that returns the majority element(if there is one, else return -1) and it must be O(nlogn). This is what I got:
public class MyMajority implements Majority {
public int findMajority(Sequence numbers) {
if (numbers.size()==0) {
return -1;
}
return major(numbers,0,numbers.size()-1);
}
public int major(Sequence numbers, int low, int high) {
if (low == high){
return numbers.get(low);
}
int mid = (high - low) / 2 + low;
int left_major = major(numbers, low, mid);
int right_major = major(numbers, mid + 1, high);
if (left_major == right_major){
return left_major;
}
int left_count = getFrequency(numbers, left_major);
int right_count = getFrequency(numbers, right_major);
return left_count > numbers.size() / 2 ? left_major :
(right_count > numbers.size() / 2 ? right_major : -1);
}
public int getFrequency(Sequence numbers, int major) {
int count = 0;
for(int i=0; i<numbers.size(); i++){
if(numbers.get(i)==major){
count++;
if(count> numbers.size()/2){
break;
}
}
}
return count;
}
However if I run the code some testcases say your algorithm is too slow.
But I'm pretty sure this is O(nlogn) am I missing something? Because I use divide and conquer and loop over the array so T(n)=2T(n/2)+O(n)=O(nlogn)

Maybe you can try this approach, which should be O(nlogn):
It's just simple sort and find the majority item. Since the requirement indicated there is always a majority number, so here it did not consider the edge case.
public class Solution {
public int majorityElement(int[] nums) {
int len = nums.length;
Arrays.sort(nums);
return nums[len/2];
}
}

Related

What is the time complexity of this algorithm that has binary search along with while loops?

I'm trying to figure out the running time complexity of the findingDup algorithm because I'm unsure if it's O(n) or O(log n). My goal is to implement a sublinear algorithm that finds how many times an int value is duplicated. You can assume the given array int[] A is always sorted. If you have any additional questions please leave them below.
public class Controller {
public static void main(String[] args){
int[] A = {-1, 2, 3, 5, 6, 6, 6, 9, 10};
int value = 6;
System.out.println(findingDup(A, value));
}// end main
public static int findingDup(int[] a, int x){
int counter = 0;
int index = binarySearch(a, x); // index = 4
int leftIndex = index - 1; // leftIndex = 3
int rightIndex = index + 1; // rightIndex = 5
if(index == -1){
return 0;
}
else if(a[index] == x){
counter++;
}
// checking if all numbers are dups
if(a[0] == a[a.length - 1]){
return a.length;
}
if(leftIndex >= 0){
while(a[leftIndex] == x){
counter++;
leftIndex--;
if(leftIndex < 0){
break;
}
}
}
if(rightIndex <= a.length - 1){
while(a[rightIndex] == x){
counter++;
rightIndex++;
if(rightIndex > a.length - 1){
break;
}
}
}
return counter;
}// end method
public static int binarySearch(int[] a, int x){
int low = 0, high = a.length - 1;
while(low <= high){
int mid = (low + high) / 2;
if(a[mid] < x){
low = mid + 1;
}
else if(a[mid] > x){
high = mid - 1;
}
else{
return mid;
}
}
return -1;
}// End Method
}// end class
Your code is O(k + log n), where "k" is number of times the value is present on the list.
If the k = O(n) it degrades to O(n).
As an example, in the extreme case of the list being [6, 6, 6, 6, 6, ...] you will end-up processing all the elements.
You can still fix this problem by running more than one binary search.
First you run it to find first occurrence of "value", and then you run it again to find a first number larger than value (search for value+1).
Your binary search algorithm needs to be modified to return the first occurrence of the value, or larger value if the value cannot be found.
As of now it finds any occurrence, not guaranteed to be the first one nor the last one.
Your binary search has the following condition:
if (smaller) {...}
else if (larger) {...}
else {we have found it!}
So it can return any occurrence.
You should be looking for an index that:
a[mid - 1] < value && a[mid] >= value
mid-1 can be smaller than 0, so you need to check for that first.
If this is not the case, we haven't found the first occurrence, and need to move either left or right index.

find if given pack of coins can make a given value - coin row problem

given array of coins (int) and an int n the function need to return true if there is atleast one solution to the coin-change problem.
meaning: for array of ints> 0: [c(0) ,c(1) ,c(2) ,c(3) ,...... ,c(k)]. check if there is a solution for
the eqauation: a(0)*c(0)+ a(1)*c(1)+.....+ a(k)*c(k)= n. //n is the money we need to change
given c(0),c(1),....,c(n) >0 and a(0),a(1),....,a(n) =>0 both integers.
so I managed to make this code: the problem is that its algorithmic efficiency sucks, and this should be running on high values, and big coins array, so I need a code that is able to do this quicker.
public static boolean change(int[] coins, int n) {
boolean ans = false;
//loop running in recursion till founds ans/ passing limit
for (int i = 0; i < coins.length & (!ans); i = i + 1) {
if (n % coins[i] == 0) {
return true;
}
if (n >= coins[i]) {
ans = change(coins, n - coins[i]);
}
}
return ans;
}//O(n*k^n) solution for false ans , very bad :(
for example: for coins = {2,4,8} and n= 4111; I should get false, but the program unable to run this.
btw I would prefer this function to use recursion, but any solution/ guidnes is good :)
this is an other try doing this better but still not running as wanted.
//trying to use binary search and using divisions instead of minus
public static int iscashable(int[] coins, int n, int min, int max)
{
int check=(max+min)/2;
if(check == coins.length-1 | check == 0)
return check;
if(n/coins[check] > n% coins[check])
{
return (iscashable(coins,n,check,max));
}
else
{
return check;
}
}
public static int canchange(int[] coins, int n, int count)
{
int x=0;
int check= iscashable(coins,n,0,coins.length-count);
if(n%coins[check]==0)
{
return 0;
}
if(check==0)
{
return n;
}
if(n/coins[check] > n% coins[check])
{
x= (n/coins[check]) - (n% coins[check]);
int k= n-(coins[check]*x);
return canchange(coins, k, count+1);
}
else
{
return canchange(coins,n-coins[check],count+1);
}
}
the problem is both about runtime and number of recursion calls (with big number given, every recursion layer is coins.length^(num of layers));
I really thank you for your help!

Insert an element to Array List sorted descending order

I'm trying to insert an element in the correct position in an array list that is sorted in descending order.
The complexity to find the correct position must be O(LOGN).
That's why I tried using binary search to find the correct position.
This is what I did:
I added:
middle = (low + high) / 2;
after the while loop.
The problem is that it's inserting the elements in ascending order. instead of descending order
public void insert(E x) {
if(q.size()==0){
q.add(0, x);
}
else{
int place = binarySearch(x);
q.add(place, x);
}
}
private int binarySearch (E x) {
int size = q.size();
int low = 0;
int high = size - 1;
int middle = 0;
while(high > low) {
middle = (low + high) / 2;
if(q.get(middle).getPriority() == x.getPriority()) {
return middle;
}
if(q.get(middle).getPriority() < x.getPriority()) {
low = middle + 1;
}
if(q.get(middle).getPriority() > x.getPriority()) {
high = middle - 1;
}
}
middle = (low + high) / 2;
if(q.get(middle).getPriority() < x.getPriority()) {
return middle + 1 ;
}
return middle;
}
There are a few problems with your code:
all your comparisons are the wrong way, thus you are inserting in ascending order
you should loop while (high >= low), or you can not insert an element that's smaller than all the existing elements; also, with this you no longer need the if/else in insert
if you want ties to be handled such that the oldest element is sorted first, remove the "same as middle" check and reverse the if/else within the loop; this way, in case of ties, the low bound is raised, inserting the new element after the older one
now, after the while loop, you can just return low
This seems to work (Note: Changed to Integer instead of E for testing, populating an initially empty list with random integers.):
public void insert(E x) {
q.add(binarySearch(x), x);
}
private int binarySearch (E x) {
int low = 0;
int high = q.size() - 1;
while (high >= low) {
int middle = (low + high) / 2;
if (q.get(middle).getPriority() < x.getPriority()) {
high = middle - 1;
} else {
low = middle + 1;
}
}
return low;
}
Tests and example output:
#Data #AllArgsConstructor
class E {
int id, priority;
public String toString() { return String.format("%d/%d", id, priority); }
}
Random random = new Random();
int id = 0;
for (int i = 0; i < 50; i++) {
test.insert(new E(id++, random.nextInt(20)));
}
System.out.println(test.q);
// [2/19, 3/19, 24/19, 32/19, 46/19, 18/18, 23/18, 39/18, 31/17, 10/16, 28/16, 40/16, 45/16, 7/15, 19/14, 33/14, 37/14, 38/14, 36/13, 44/13, 5/11, 12/11, 15/11, 20/11, 30/11, 9/10, 41/10, 48/10, 16/9, 34/9, 13/8, 1/7, 8/7, 35/7, 0/6, 6/6, 22/6, 29/6, 21/5, 26/5, 42/5, 14/4, 27/4, 47/4, 25/3, 4/1, 11/1, 17/1, 43/1, 49/0]
This could be a lot simpler using Collections.binarySearch. The methods will return the index if it is found or return a negative value matching where it should be :
the index of the search key, if it is contained in the list; otherwise, (-(insertion point) - 1). The insertion point is defined as the point at which the key would be inserted into the list: the index of the first element greater than the key, or list.size() if all elements in the list are less than the specified key. Note that this guarantees that the return value will be >= 0 if and only if the key is found.
Here is a quick example of a SortedList
class SortedList<E> extends ArrayList<E>{
Comparator<E> comparator;
public SortedList(Comparator<E> comparator) {
this.comparator = comparator;
}
#Override
public boolean add(E e) {
int index = Collections.binarySearch(this, e, comparator);
if(index < 0){
index = -index - 1;
}
if(index >= this.size()){
super.add(e);
} else {
super.add(index, e);
}
return true;
}
}
And a test case for a descending order:
SortedList<Integer> list = new SortedList<>(
(i1, i2) -> i2 - i1
);
list.add(10);
list.add(20);
list.add(15);
list.add(10);
System.out.println(list);
[20, 15, 10, 10]
The comparator in the constructor allow you to set the order to use for the insertion. Not that this is not safe, this is not overriding every methods but this is a quick answer ;)

Arrays.binarySearch next index [duplicate]

This question already has answers here:
Finding multiple entries with binary search
(15 answers)
Closed 3 years ago.
I've been tasked with creating a method that will print all the indices where value x is found in a sorted array.
I understand that if we just scanned through the array from 0 to N (length of array) it would have a running time of O(n) worst case. Since the array that will be passed into the method will be sorted, I'm assuming that I can take advantage of using a Binary Search since this will be O(log n). However, this only works if the array has unique values. Since the Binary Search will finish after the first "find" of a particular value. I was thinking of doing a Binary Search for finding x in the sorted array, and then checking all values before and after this index, but then if the array contained all x values, it doesn't seem like it would be that much better.
I guess what I'm asking is, is there a better way to find all the indices for a particular value in a sorted array that is better than O(n)?
public void PrintIndicesForValue42(int[] sortedArrayOfInts)
{
// search through the sortedArrayOfInts
// print all indices where we find the number 42.
}
Ex: sortedArray = { 1, 13, 42, 42, 42, 77, 78 } would print: "42 was found at Indices: 2, 3, 4"
You will get the result in O(lg n)
public static void PrintIndicesForValue(int[] numbers, int target) {
if (numbers == null)
return;
int low = 0, high = numbers.length - 1;
// get the start index of target number
int startIndex = -1;
while (low <= high) {
int mid = (high - low) / 2 + low;
if (numbers[mid] > target) {
high = mid - 1;
} else if (numbers[mid] == target) {
startIndex = mid;
high = mid - 1;
} else
low = mid + 1;
}
// get the end index of target number
int endIndex = -1;
low = 0;
high = numbers.length - 1;
while (low <= high) {
int mid = (high - low) / 2 + low;
if (numbers[mid] > target) {
high = mid - 1;
} else if (numbers[mid] == target) {
endIndex = mid;
low = mid + 1;
} else
low = mid + 1;
}
if (startIndex != -1 && endIndex != -1){
for(int i=0; i+startIndex<=endIndex;i++){
if(i>0)
System.out.print(',');
System.out.print(i+startIndex);
}
}
}
Well, if you actually do have a sorted array, you can do a binary search until you find one of the indexes you're looking for, and from there, the rest should be easy to find since they're all next to each-other.
once you've found your first one, than you go find all the instances before it, and then all the instances after it.
Using that method you should get roughly O(lg(n)+k) where k is the number of occurrences of the value that you're searching for.
EDIT:
And, No, you will never be able to access all k values in anything less than O(k) time.
Second edit: so that I can feel as though I'm actually contributing something useful:
Instead of just searching for the first and last occurrences of X than you can do a binary search for the first occurence and a binary search for the last occurrence. which will result in O(lg(n)) total. once you've done that, you'll know that all the between indexes also contain X(assuming that it's sorted)
You can do this by searching checking if the value is equal to x , AND checking if the value to the left(or right depending on whether you're looking for the first occurrence or the last occurrence) is equal to x.
public void PrintIndicesForValue42(int[] sortedArrayOfInts) {
int index_occurrence_of_42 = left = right = binarySearch(sortedArrayOfInts, 42);
while (left - 1 >= 0) {
if (sortedArrayOfInts[left-1] == 42)
left--;
}
while (right + 1 < sortedArrayOfInts.length) {
if (sortedArrayOfInts[right+1] == 42)
right++;
}
System.out.println("Indices are from: " + left + " to " + right);
}
This would run in O(log(n) + #occurrences)
Read and understand the code. It's simple enough.
Below is the java code which returns the range for which the search-key is spread in the given sorted array:
public static int doBinarySearchRec(int[] array, int start, int end, int n) {
if (start > end) {
return -1;
}
int mid = start + (end - start) / 2;
if (n == array[mid]) {
return mid;
} else if (n < array[mid]) {
return doBinarySearchRec(array, start, mid - 1, n);
} else {
return doBinarySearchRec(array, mid + 1, end, n);
}
}
/**
* Given a sorted array with duplicates and a number, find the range in the
* form of (startIndex, endIndex) of that number. For example,
*
* find_range({0 2 3 3 3 10 10}, 3) should return (2,4). find_range({0 2 3 3
* 3 10 10}, 6) should return (-1,-1). The array and the number of
* duplicates can be large.
*
*/
public static int[] binarySearchArrayWithDup(int[] array, int n) {
if (null == array) {
return null;
}
int firstMatch = doBinarySearchRec(array, 0, array.length - 1, n);
int[] resultArray = { -1, -1 };
if (firstMatch == -1) {
return resultArray;
}
int leftMost = firstMatch;
int rightMost = firstMatch;
for (int result = doBinarySearchRec(array, 0, leftMost - 1, n); result != -1;) {
leftMost = result;
result = doBinarySearchRec(array, 0, leftMost - 1, n);
}
for (int result = doBinarySearchRec(array, rightMost + 1, array.length - 1, n); result != -1;) {
rightMost = result;
result = doBinarySearchRec(array, rightMost + 1, array.length - 1, n);
}
resultArray[0] = leftMost;
resultArray[1] = rightMost;
return resultArray;
}
Another result for log(n) binary search for leftmost target and rightmost target. This is in C++, but I think it is quite readable.
The idea is that we always end up when left = right + 1. So, to find leftmost target, if we can move right to rightmost number which is less than target, left will be at the leftmost target.
For leftmost target:
int binary_search(vector<int>& nums, int target){
int n = nums.size();
int left = 0, right = n - 1;
// carry right to the greatest number which is less than target.
while(left <= right){
int mid = (left + right) / 2;
if(nums[mid] < target)
left = mid + 1;
else
right = mid - 1;
}
// when we are here, right is at the index of greatest number
// which is less than target and since left is at the next,
// it is at the first target's index
return left;
}
For the rightmost target, the idea is very similar:
int binary_search(vector<int>& nums, int target){
while(left <= right){
int mid = (left + right) / 2;
// carry left to the smallest number which is greater than target.
if(nums[mid] <= target)
left = mid + 1;
else
right = mid - 1;
}
// when we are here, left is at the index of smallest number
// which is greater than target and since right is at the next,
// it is at the first target's index
return right;
}
I came up with the solution using binary search, only thing is to do the binary search on both the sides if the match is found.
public static void main(String[] args) {
int a[] ={1,2,2,5,5,6,8,9,10};
System.out.println(2+" IS AVAILABLE AT = "+findDuplicateOfN(a, 0, a.length-1, 2));
System.out.println(5+" IS AVAILABLE AT = "+findDuplicateOfN(a, 0, a.length-1, 5));
int a1[] ={2,2,2,2,2,2,2,2,2};
System.out.println(2+" IS AVAILABLE AT = "+findDuplicateOfN(a1, 0, a1.length-1, 2));
int a2[] ={1,2,3,4,5,6,7,8,9};
System.out.println(10+" IS AVAILABLE AT = "+findDuplicateOfN(a2, 0, a2.length-1, 10));
}
public static String findDuplicateOfN(int[] a, int l, int h, int x){
if(l>h){
return "";
}
int m = (h-l)/2+l;
if(a[m] == x){
String matchedIndexs = ""+m;
matchedIndexs = matchedIndexs+findDuplicateOfN(a, l, m-1, x);
matchedIndexs = matchedIndexs+findDuplicateOfN(a, m+1, h, x);
return matchedIndexs;
}else if(a[m]>x){
return findDuplicateOfN(a, l, m-1, x);
}else{
return findDuplicateOfN(a, m+1, h, x);
}
}
2 IS AVAILABLE AT = 12
5 IS AVAILABLE AT = 43
2 IS AVAILABLE AT = 410236578
10 IS AVAILABLE AT =
I think this is still providing the results in O(logn) complexity.
A Hashmap might work, if you're not required to use a binary search.
Create a HashMap where the Key is the value itself, and then value is an array of indices where that value is in the array. Loop through your array, updating each array in the HashMap for each value.
Lookup time for the indices for each value will be ~ O(1), and creating the map itself will be ~ O(n).
Find_Key(int arr[], int size, int key){
int begin = 0;
int end = size - 1;
int mid = end / 2;
int res = INT_MIN;
while (begin != mid)
{
if (arr[mid] < key)
begin = mid;
else
{
end = mid;
if(arr[mid] == key)
res = mid;
}
mid = (end + begin )/2;
}
return res;
}
Assuming the array of ints is in ascending sorted order; Returns the index of the first index of key occurrence or INT_MIN. Runs in O(lg n).
It is using Modified Binary Search. It will be O(LogN). Space complexity will be O(1).
We are calling BinarySearchModified two times. One for finding start index of element and another for finding end index of element.
private static int BinarySearchModified(int[] input, double toSearch)
{
int start = 0;
int end = input.Length - 1;
while (start <= end)
{
int mid = start + (end - start)/2;
if (toSearch < input[mid]) end = mid - 1;
else start = mid + 1;
}
return start;
}
public static Result GetRange(int[] input, int toSearch)
{
if (input == null) return new Result(-1, -1);
int low = BinarySearchModified(input, toSearch - 0.5);
if ((low >= input.Length) || (input[low] != toSearch)) return new Result(-1, -1);
int high = BinarySearchModified(input, toSearch + 0.5);
return new Result(low, high - 1);
}
public struct Result
{
public int LowIndex;
public int HighIndex;
public Result(int low, int high)
{
LowIndex = low;
HighIndex = high;
}
}
public void printCopies(int[] array)
{
HashMap<Integer, Integer> memberMap = new HashMap<Integer, Integer>();
for(int i = 0; i < array.size; i++)
if(!memberMap.contains(array[i]))
memberMap.put(array[i], 1);
else
{
int temp = memberMap.get(array[i]); //get the number of occurances
memberMap.put(array[i], ++temp); //increment his occurance
}
//check keys which occured more than once
//dump them in a ArrayList
//return this ArrayList
}
Alternatevely, instead of counting the number of occurances, you can put their indices in a arraylist and put that in the map instead of the count.
HashMap<Integer, ArrayList<Integer>>
//the integer is the value, the arraylist a list of their indices
public void printCopies(int[] array)
{
HashMap<Integer, ArrayList<Integer>> memberMap = new HashMap<Integer, ArrayList<Integer>>();
for(int i = 0; i < array.size; i++)
if(!memberMap.contains(array[i]))
{
ArrayList temp = new ArrayList();
temp.add(i);
memberMap.put(array[i], temp);
}
else
{
ArrayList temp = memberMap.get(array[i]); //get the lsit of indices
temp.add(i);
memberMap.put(array[i], temp); //update the index list
}
//check keys which return lists with length > 1
//handle the result any way you want
}
heh, i guess this will have to be posted.
int predefinedDuplicate = //value here;
int index = Arrays.binarySearch(array, predefinedDuplicate);
int leftIndex, rightIndex;
//search left
for(leftIndex = index; array[leftIndex] == array[index]; leftIndex--); //let it run thru it
//leftIndex is now the first different element to the left of this duplicate number string
for(rightIndex = index; array[rightIndex] == array[index]; rightIndex++); //let it run thru it
//right index contains the first different element to the right of the string
//you can arraycopy this [leftIndex+1, rightIndex-1] string or just print it
for(int i = leftIndex+1; i<rightIndex; i++)
System.out.println(array[i] + "\t");

Finding Max of an array using Recursion

So it's pretty simple to find the max of an array using a for loop or a while loop, but I wanted to try it out with recursion. For some reason, the substring doesn't work - it says "cannot find symbol". Why is this? My strategy is continue subdividing and comparing the two sides until there is only one left which should be the max....am I doing it right? Thanks
public static int max(int[] array) {
if (array.length == 1) {
return array[0];
} else {
int mid = (array.length) / 2;
int leftmax = max(array.substring(0, mid));
int rightmax = max(array.substring(mid, array.length));
if (leftmax > rightmax) {
return leftmax;
} else {
return rightmax;
}
}
}
You are going to want to use Arrays.copyOfRange. Substring isn't going to work on an array.
int[] firstHalf = Arrays.copyOfRange(original, 0, original.length/2);
int[] secondHalf = Arrays.copyOfRange(original, original.length/2, original.length);
I can't comment on your algorithm.
Since array is of type int[] not String, you cannot use substring(). Instead, keep track of which indexes you are searching through. Copying the array each iteration is a waste of both space and time.
int max( int[] array ){ return max( array, 0, array.length - 1 ); }
int max( int[] array, int low, int high )
{
if (low == high) {
return array[low];
}
else {
int mid = (high + low) / 2;
int leftmax = max(array, low, mid );
int rightmax = max(array, mid, high );
if (leftmax > rightmax) {
return leftmax;
}
else {
return rightmax;
}
}
}

Categories