Related
I am practicing recursive algorithms because although I love recursion, I am still having trouble when there is "double" recursion going on. So I created this brute force 0-1 Knapsack algorithm which will output the final weight and best value, and its pretty good, but I decided that information is only relevant if you know which items are behind those numbers. I am stuck here, though. I want to do this elegantly, without creating a mess of code, and perhaps I am over-limiting my thinking trying to meet that goal. I thought I would post the code here and see if anyone had some nifty ideas about adding code to output the chosen items. This is Java:
public class Knapsack {
static int num_items = 4;
static int weights[] = { 3, 5, 1, 4 };
static int benefit[] = { 2, 4, 3, 6 };
static int capacity = 10;
static int new_sack[] = new int[num_items];
static int max_value = 0;
static int weight = 0;
// O(n2^n) brute force algorithm (i.e. check all combinations) :
public static void findMaxValue(int n, int currentWeight, int currentValue) {
if ((n == 0) && (currentWeight <= capacity) && (currentValue > max_value)) {
max_value = currentValue;
weight = currentWeight;
}
if (n == 0) {
return;
}
findMaxValue(n - 1, currentWeight, currentValue);
findMaxValue(n - 1, currentWeight + weights[n - 1], currentValue + benefit[n - 1]);
}
public static void main(String[] args) {
findMaxValue(num_items, 0, 0);
System.out.println("The max value you can get is: " + max_value + " with weight: " + weight);
// System.out.println(Arrays.toString(new_sack));
}
}
The point of the 0-1 Knapsack algorithm is to find if excluding or including an item in the knapsack results in a higher value. Your code doesn't compare these two possibilities. The code to do this would look like:
public int knapsack(int[] weights, int[] values, int n, int capacity) {
if (n == 0 || capacity == 0)
return 0;
if (weights[n-1] > capacity) // if item won't fit in knapsack
return knapsack(weights, values, n-1, capacity); // look at next item
// Compare if excluding or including item results in greater value
return max(
knapsack(weights, values, n-1, capacity), // exclude item
values[n] + knapsack(weights, values, n-1, capacity - weights[n-1])); // include item
}
I'm trying to write an algorithm for finding the index of the closest value that is lesser than or equal to the search value in a sorted array. In the example of the array [10, 20, 30], the following search values should output these indexes:
searchValue: 9, index: -1
searchValue: 10, index: 0
searchValue: 28, index: 1
searchValue: 55555, index: 2
I want to use binary search for logarithmic runtime. I have an algorithm in C-esque psuedocode, but it has 3 base cases. Can these 3 base cases be condensed into 1 for a more elegant solution?
int function indexOfClosestLesser(array, searchValue, startIndex, endIndex) {
if (startIndex == endIndex) {
if (searchValue >= array[startIndex]) {
return startIndex;
} else {
return -1;
}
}
// In the simplistic case of searching for 2 in [0, 2], the midIndex
// is always 0 due to int truncation. These checks are to avoid recursing
// infinitely from index 0 to index 1.
if (startIndex == endIndex - 1) {
if (searchValue >= array[endIndex]) {
return endIndex;
} else if (searchValue >= array[startIndex]) {
return startIndex;
} else {
return -1;
}
}
// In normal binary search, this would be the only base case
if (startIndex < endIndex) {
return -1;
}
int midIndex = endIndex / 2 + startIndex / 2;
int midValue = array[midIndex];
if (midValue > searchValue) {
return indexOfClosestLesser(array, searchValue, startIndex, midIndex - 1);
} else if (searchValue >= midValue) {
// Unlike normal binary search, we don't start on midIndex + 1.
// We're not sure whether the midValue can be excluded yet
return indexOfClosestLesser(array, searchValue, midIndex, endIndex);
}
}
Based on your recursive approach, I would suggest the following c++ snippet that reduces the number of different cases a bit:
int search(int *array, int start_idx, int end_idx, int search_val) {
if( start_idx == end_idx )
return array[start_idx] <= search_val ? start_idx : -1;
int mid_idx = start_idx + (end_idx - start_idx) / 2;
if( search_val < array[mid_idx] )
return search( array, start_idx, mid_idx, search_val );
int ret = search( array, mid_idx+1, end_idx, search_val );
return ret == -1 ? mid_idx : ret;
}
Basically it performs a normal binary search. It only differs in the return statement of the last case to fulfill the additional requirement.
Here is a short test program:
#include <iostream>
int main( int argc, char **argv ) {
int array[3] = { 10, 20, 30 };
std::cout << search( array, 0, 2, 9 ) << std::endl;
std::cout << search( array, 0, 2, 10 ) << std::endl;
std::cout << search( array, 0, 2, 28 ) << std::endl;
std::cout << search( array, 0, 2, 55555 ) << std::endl;
return 0;
}
The output is as desired:
-1
0
1
2
Frankly speaking, I find the logic of finding a number greater than a given number a lot easier than the logic needed to find numbers less than or equal to a given number. Obviously, the reason behind that is the extra logic (that forms the edge cases) required to handle the duplicate numbers (of given num) present in the array.
public int justGreater(int[] arr, int val, int s, int e){
// Returns the index of first element greater than val.
// If no such value is present, returns the size of the array.
if (s >= e){
return arr[s] <= N ? s+1 : s;
}
int mid = (s + e) >> 1;
if (arr[mid] < val) return justGreater(arr, val, mid+1, e);
return justGreater(arr, val, s, mid);
}
and then to find the index of the closest value that is lesser than or equal to the search value in a sorted array, just subtract the returned value by 1:
ans = justGreater(arr, val, 0, arr.length-1) - 1;
Trick
The trick here is to search for searchValue + 1 and return the the found index as index - 1 which is left - 1 in the code below
For example if we search for 9 in [10, 20, 30]. The code will look for 10 and return that it's present at 0th index and we return 0-1 which is -1
Similarly if we try to search for 10 in the above example it will search for 10 + 1 and return 1st index and we return 1-1 which is 0
Code
def binary_search(array, searchValue, startIndex=0, endIndex=2 ** 32):
"""
Binary search for the closest value less than or equal to the search value
:param array: The given sorted list
:param searchValue: Value to be found in the array
:param startIndex: Initialized with 0
:param endIndex: Initialized with 2**32
:return: Returns the index closest value less than or equal to the search value
"""
left = max(0, startIndex)
right = min(len(array), endIndex)
while left < right:
mid = (left + right) // 2
if array[mid] < searchValue + 1:
left = mid + 1
else:
right = mid
return left - 1
It can also be done in a single line with the standard library.
import bisect
def standard_binary_search(array, searchVal):
return bisect.bisect_left(array, searchVal + 1) - 1
Testing
Testing the test cases provided by OP
array = [10, 20, 30]
print(binary_search(array, 9))
print(binary_search(array, 10))
print(binary_search(array, 28))
print(binary_search(array, 5555))
Results
-1
0
1
2
I created a linear search to test the binary search.
def linear_search(array, searchVal):
ans = -1
for i, num in enumerate(array):
if num > searchVal:
return ans
ans = i
return ans
And a function to test all the binary search functions above.
Check for correctness
def check_correctness(array, searchVal):
assert binary_search(array, searchVal) == linear_search(array, searchVal)
assert binary_search(array, searchVal) == standard_binary_search(array, searchVal)
return binary_search(array, searchVal)
Driver Function
nums = sorted(
[460, 4557, 1872, 2698, 4411, 1730, 3870, 4941, 77, 7789, 8553, 6011, 9882, 9597, 8060, 1518, 8210, 380, 6822, 9022,
8255, 8977, 2492, 5918, 3710, 4253, 8386, 9660, 2933, 7880, 615, 1439, 9311, 3526, 5674, 1899, 1544, 235, 3369,
519, 8018, 8489, 3093, 2547, 4903, 1836, 2447, 570, 7666, 796, 7149, 9623, 681, 1869, 4381, 2711, 9882, 4348, 4617,
7852, 5897, 4135, 9471, 4202, 6630, 3037, 9694, 9693, 7779, 3041, 3160, 4911, 8022, 7909, 297, 7258, 4379, 3216,
9474, 8876, 6108, 7814, 9484, 2868, 882, 4206, 3986, 3038, 3659, 3287, 2152, 2964, 7057, 7122, 261, 2716, 4845,
3709, 3562, 1928]
)
for num in range(10002):
ans = check_correctness(nums, num)
if ans != -1:
print(num, nums[check_correctness(nums, num)])
The driver function ran without any assert errors. This proves the correctness of the above two functions.
Commented version in typescript. Based on this answer but modified to return less than or equal to.
/**
* Binary Search of a sorted array but returns the closest smaller value if the
* needle is not in the array.
*
* Returns null if the needle is not in the array and no smaller value is in
* the array.
*
* #param haystack the sorted array to search #param needle the need to search
* for in the haystack #param compareFn classical comparison function, return
* -1 if a is less than b, 0 if a is equal to b, and 1 if a is greater than b
*/
export function lessThanOrEqualBinarySearch<T>(
haystack: T[],
needle: T,
compareFn: (a: T, b: T) => number
): T | null {
let lo = 0;
let hi = haystack.length - 1;
let lowestFound: T | null = null;
// iteratively search halves of the array but when we search the larger
// half keep track of the largest value in the smaller half
while (lo <= hi) {
let mid = (hi + lo) >> 1;
let cmp = compareFn(needle, haystack[mid]);
// needle is smaller than middle
// search in the bottom half
if (cmp < 0) {
hi = mid - 1;
continue;
}
// needle is larger than middle
// search in the top half
else if (cmp > 0) {
lo = mid + 1;
lowestFound = haystack[mid];
} else if (cmp === 0) {
return haystack[mid];
}
}
return lowestFound;
}
Here's a PHP version, based on user0815's answer.
Adapted it to take a function, not just an array, and made it more efficient by avoiding evaluation of $mid_idx twice.
function binarySearchLessOrEqual($start_idx, $end_idx, $search_val, $valueFunction)
{
//N.B. If the start index is bigger or equal to the end index, we've reached the end!
if( $start_idx >= $end_idx )
{
return $valueFunction($end_idx) <= $search_val ? $end_idx : -1;
}
$mid_idx = intval($start_idx + ($end_idx - $start_idx) / 2);
if ( $valueFunction($mid_idx) > $search_val ) //If the function is too big, we search in the bottom half
{
return binarySearchLessOrEqual( $start_idx, $mid_idx-1, $search_val, $valueFunction);
}
else //If the function returns less than OR equal, we search in the top half
{
$ret = binarySearchLessOrEqual($mid_idx+1, $end_idx, $search_val, $valueFunction);
//If nothing is suitable, then $mid_idx was actually the best one!
return $ret == -1 ? $mid_idx : $ret;
}
}
Rather than taking an array, it takes a int-indexed function. You could easily adapt it to take an array instead, or simply use it as below:
function indexOfClosestLesser($array, $searchValue)
{
return binarySearchLessOrEqual(
0,
count($array)-1,
$searchValue,
function ($n) use ($array)
{
return $array[$n];
}
);
}
Tested:
$array = [ 10, 20, 30 ];
echo "0: " . indexOfClosestLesser($array, 0) . "<br>"; //-1
echo "5: " . indexOfClosestLesser($array, 5) . "<br>"; //-1
echo "10: " . indexOfClosestLesser($array, 10) . "<br>"; //0
echo "15: " . indexOfClosestLesser($array, 15) . "<br>"; //0
echo "20: " . indexOfClosestLesser($array, 20) . "<br>"; //1
echo "25: " . indexOfClosestLesser($array, 25) . "<br>"; //1
echo "30: " . indexOfClosestLesser($array, 30) . "<br>"; //2
echo "35: " . indexOfClosestLesser($array, 35) . "<br>"; //2
Try using a pair of global variables, then reference those variables inside the COMPARE function for bsearch
In RPGIV we can call c functions.
The compare function with global variables looks like this:
dcl-proc compInvHdr;
dcl-pi compInvHdr int(10);
elmPtr1 pointer value;
elmPtr2 pointer value;
end-pi;
dcl-ds elm1 based(elmPtr1) likeds(invHdr_t);
dcl-ds elm2 based(elmPtr2) likeds(elm1);
dcl-s low int(10) inz(-1);
dcl-s high int(10) inz(1);
dcl-s equal int(10) inz(0);
select;
when elm1.rcd.RECORDNO < elm2.rcd.RECORDNO;
lastHiPtr = elmPtr2;
return low;
when elm1.rcd.RECORDNO > elm2.rcd.RECORDNO;
lastLoPtr = elmPtr2;
return high;
other;
return equal;
endsl;
end-proc;
Remember, that in bsearch the first element is the search key and the second element is the actual storage element in your array/memory, that is why the COMPARE procedure is using elmPtr2;
the call to bsearch looks like this:
// lastLoPtr and LastHiPtr are global variables
// basePtr points to the beginning of the array
lastLoPtr = basePtr;
lastHiPtr = basePtr + ((numRec - 1) * sizRec));
searchKey = 'somevalue';
hitPtr = bsearch(%addr(searchkey)
:basePtr
:numRec
:sizRec
:%PADDR('COMPINVHDR'));
if hitPtr <> *null;
//? not found
hitPtr = lastLoPtr;
else;
//? found
endif;
So if the key is not found then the hitPtr is set to the key of the closest match, effectively archiving a "Less than or Equal key".
If you want the opposite, the next greater key. Then use lastHiPtr to reference the first key greater than the search key.
Note: protect the global variables against race conditions (if applicable).
Wanted to provide a non-binary search way of doing this, in C#. The following finds the closest value to X, without being greater than X, but it can be equal to X. My function also does not need the list to be sorted. It is also theoretically faster than O(n), but only in the event that the exact target number is found, in which case it terminates early and returns the integer.
public static int FindClosest(List<int> numbers, int target)
{
int current = 0;
int difference = Int32.MaxValue;
foreach(int integer in numbers)
{
if(integer == target)
{
return integer;
}
int diff = Math.Abs(target - integer);
if(integer <= target && integer >= current && diff < difference)
{
current = integer;
difference = diff;
}
}
return current;
}
I tested this with the following setup, and it appears to be working flawlessly:
List<int> values = new List<int>() {1,24,32,6,14,9,11,22 };
int target = 21;
int closest = FindClosest(values,target);
Console.WriteLine("Closest: " + closest);
7 years later, I hope to provide some intuition:
If search_val <= arr[mid], we know for the sure that the solution resides in the interval [lo, mid], inclusive. So, we set right=mid (we probably can set right=mid-1 if mid is not included). Note that if search_val < arr[mid], we in fact know that the solution resides in [lo, mid), mid not inclusive. This is because search_val won't fall back on mid and use mid as the closest value <= search value if it is less than arr[mid].
On the other hand, search_val >= arr[mid]. In this case, we know that the solution resides in [mid, hi]. In fact, even if search_val > arr[mid], the solution is still [mid, hi]. This means that we should set left = mid. HOWEVER, in binary search, left is usually always set to mid + 1 to avoid infinite loops. But this means, when the loops at left==right, it is possible we are 1 index over the solution. Thus, we do a check at the very end to return either the left or left-1, that you can see in the other solutions.
Practice Problem: Search a 2D Matrix
Write an efficient algorithm that searches for a value target in an m x n integer matrix matrix. This matrix has the following properties:
Integers in each row are sorted from left to right.
The first integer of each row is greater than the last integer of the
previous row.
The smart solution to this problem is to treat the two-dimensional array as an one-dimensional one and use regular binary search. But I wrote a solution that first locates the correct row. The process of finding the correct row in this problem is basically the same as finding the closest value less than equal to the search value.
Additionally link on binary search: Useful Insights into Binary Search
a non-recursive way using loop, I'm using this in javascript so I'll just post in javascript:
let left = 0
let right = array.length
let mid = 0
while (left < right) {
mid = Math.floor((left + right) / 2)
if (searchValue < array[mid]) {
right = mid
} else {
left = mid + 1
}
}
return left - 1
since general guideline tells us to look at the middle pointer, many fail to see that the actual answer is the left pointer's final value.
This is question asked in one of the interview. Please suggest some view.
Given an array containing all positive integers. You have to arrange elements in such a way that odd elements are at odd position and even elements are at even positions.
PS. No extra space. O(N) solution
Iterate over the even positions until you find an odd number. Iterate over the odd positions until you find and even number (using a different index). Swap the two numbers, and repeat.
Are you allowed to double the size of the array? Otherwise, the question doesn't make sense. Why?!? assume you are given an array full of odd numbers, can you think of any solution then? No, there is not.
So, I assume that you are allowed to double the size of the array. Then for any i, put the i-element ( a(i) ) into the location 2*i or 2*i +1 depending on whether a(i) is even or odd resp.
Two two new Arrays OddArray and EvenArray of same size as that of given array. Traverse through the given array and keep sending all the odd to OddArray and keep at odd positions and even number to EvenArray keeping numbers at even positions.
The efficiency will be O(n) and extra memory will be 2n where n is the size of original array.
list1 = [5, 7, 6, 8, 10, 3, 4, 9, 2, 1, 12]
odd_list = []
even_list = []
for i in range(len(list1)):
if((list1[i] % 2) == 0):
even_list.append(list1[i])
else:
odd_list.append(list1[i])
print(list1)
j = 0
k = 0
for i in range(0, len(list1)):
if((i % 2 == 0) and (j < len(odd_list))):
list1[i] = odd_list[j]
j += 1
elif(k < len(even_list)):
list1[i] = even_list[k]
k += 1
print(list1)
//Putting even number on even position and odd number on odd position
package com.learnJava;
public class ArrangeArray {
private int [] array={2,5,7,8,1,6,9};
private int len=array.length;
public static void main(String [] args)
{
ArrangeArray a=new ArrangeArray();
a.print();
a.arrange();
a.print();
}
public void print()
{
for(int i=0;i<array.length;i++)
{
System.out.print(array[i] + " ");
}
System.out.println();
}
public void arrange()
{
int oddinx=1;
int evenidx=0;
while(true)
{
while(evenidx<len && array[evenidx]%2==0)
{
evenidx+=2;
}
while(oddinx<len && array[oddinx]%2==1)
{
oddinx+=2;
}
if (evenidx < len && oddinx < len)
swap (evenidx, oddinx);
else
break;
}
}
public void swap(int a,int b)
{
int tmp=array[b];
array[b]=array[a];
array[a]=tmp;
}
}
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 years ago.
The community reviewed whether to reopen this question 12 months ago and left it closed:
Original close reason(s) were not resolved
Improve this question
You are given as input an unsorted array of n distinct numbers, where n is a power of 2. Give an algorithm that identifies the second-largest number in the array, and that uses at most n+log₂(n)−2 comparisons.
Start with comparing elements of the n element array in odd and even positions and determining largest element of each pair. This step requires n/2 comparisons. Now you've got only n/2 elements. Continue pairwise comparisons to get n/4, n/8, ... elements. Stop when the largest element is found. This step requires a total of n/2 + n/4 + n/8 + ... + 1 = n-1 comparisons.
During previous step, the largest element was immediately compared with log₂(n) other elements. You can determine the largest of these elements in log₂(n)-1 comparisons. That would be the second-largest number in the array.
Example: array of 8 numbers [10,9,5,4,11,100,120,110].
Comparisons on level 1: [10,9] ->10 [5,4]-> 5, [11,100]->100 , [120,110]-->120.
Comparisons on level 2: [10,5] ->10 [100,120]->120.
Comparisons on level 3: [10,120]->120.
Maximum is 120. It was immediately compared with: 10 (on level 3), 100 (on level 2), 110 (on level 1).
Step 2 should find the maximum of 10, 100, and 110. Which is 110. That's the second largest element.
sly s's answer is derived from this paper, but he didn't explain the algorithm, which means someone stumbling across this question has to read the whole paper, and his code isn't very sleek as well. I'll give the crux of the algorithm from the aforementioned paper, complete with complexity analysis, and also provide a Scala implementation, just because that's the language I chose while working on these problems.
Basically, we do two passes:
Find the max, and keep track of which elements the max was compared to.
Find the max among the elements the max was compared to; the result is the second largest element.
In the picture above, 12 is the largest number in the array, and was compared to 3, 1, 11, and 10 in the first pass. In the second pass, we find the largest among {3, 1, 11, 10}, which is 11, which is the second largest number in the original array.
Time Complexity:
All elements must be looked at, therefore, n - 1 comparisons for pass 1.
Since we divide the problem into two halves each time, there are at most log₂n recursive calls, for each of which, the comparisons sequence grows by at most one; the size of the comparisons sequence is thus at most log₂n, therefore, log₂n - 1 comparisons for pass 2.
Total number of comparisons <= (n - 1) + (log₂n - 1) = n + log₂n - 2
def second_largest(nums: Sequence[int]) -> int:
def _max(lo: int, hi: int, seq: Sequence[int]) -> Tuple[int, MutableSequence[int]]:
if lo >= hi:
return seq[lo], []
mid = lo + (hi - lo) // 2
x, a = _max(lo, mid, seq)
y, b = _max(mid + 1, hi, seq)
if x > y:
a.append(y)
return x, a
b.append(x)
return y, b
comparisons = _max(0, len(nums) - 1, nums)[1]
return _max(0, len(comparisons) - 1, comparisons)[0]
The first run for the given example is as follows:
lo=0, hi=1, mid=0, x=10, a=[], y=4, b=[]
lo=0, hi=2, mid=1, x=10, a=[4], y=5, b=[]
lo=3, hi=4, mid=3, x=8, a=[], y=7, b=[]
lo=3, hi=5, mid=4, x=8, a=[7], y=2, b=[]
lo=0, hi=5, mid=2, x=10, a=[4, 5], y=8, b=[7, 2]
lo=6, hi=7, mid=6, x=12, a=[], y=3, b=[]
lo=6, hi=8, mid=7, x=12, a=[3], y=1, b=[]
lo=9, hi=10, mid=9, x=6, a=[], y=9, b=[]
lo=9, hi=11, mid=10, x=9, a=[6], y=11, b=[]
lo=6, hi=11, mid=8, x=12, a=[3, 1], y=11, b=[9]
lo=0, hi=11, mid=5, x=10, a=[4, 5, 8], y=12, b=[3, 1, 11]
Things to note:
There are exactly n - 1=11 comparisons for n=12.
From the last line, y=12 wins over x=10, and the next pass starts with the sequence [3, 1, 11, 10], which has log₂(12)=3.58 ~ 4 elements, and will require 3 comparisons to find the maximum.
I have implemented this algorithm in Java answered by #Evgeny Kluev. The total comparisons are n+log2(n)−2. There is also a good reference:
Alexander Dekhtyar: CSC 349: Design and Analyis of Algorithms. This is similar to the top voted algorithm.
public class op1 {
private static int findSecondRecursive(int n, int[] A){
int[] firstCompared = findMaxTournament(0, n-1, A); //n-1 comparisons;
int[] secondCompared = findMaxTournament(2, firstCompared[0]-1, firstCompared); //log2(n)-1 comparisons.
//Total comparisons: n+log2(n)-2;
return secondCompared[1];
}
private static int[] findMaxTournament(int low, int high, int[] A){
if(low == high){
int[] compared = new int[2];
compared[0] = 2;
compared[1] = A[low];
return compared;
}
int[] compared1 = findMaxTournament(low, (low+high)/2, A);
int[] compared2 = findMaxTournament((low+high)/2+1, high, A);
if(compared1[1] > compared2[1]){
int k = compared1[0] + 1;
int[] newcompared1 = new int[k];
System.arraycopy(compared1, 0, newcompared1, 0, compared1[0]);
newcompared1[0] = k;
newcompared1[k-1] = compared2[1];
return newcompared1;
}
int k = compared2[0] + 1;
int[] newcompared2 = new int[k];
System.arraycopy(compared2, 0, newcompared2, 0, compared2[0]);
newcompared2[0] = k;
newcompared2[k-1] = compared1[1];
return newcompared2;
}
private static void printarray(int[] a){
for(int i:a){
System.out.print(i + " ");
}
System.out.println();
}
public static void main(String[] args) {
//Demo.
System.out.println("Origial array: ");
int[] A = {10,4,5,8,7,2,12,3,1,6,9,11};
printarray(A);
int secondMax = findSecondRecursive(A.length,A);
Arrays.sort(A);
System.out.println("Sorted array(for check use): ");
printarray(A);
System.out.println("Second largest number in A: " + secondMax);
}
}
the problem is:
let's say, in comparison level 1, the algorithm need to be remember all the array element because largest is not yet known, then, second, finally, third. by keep tracking these element via assignment will invoke additional value assignment and later when the largest is known, you need also consider the tracking back. As the result, it will not be significantly faster than simple 2N-2 Comparison algorithm. Moreover, because the code is more complicated, you need also think about potential debugging time.
eg: in PHP, RUNNING time for comparison vs value assignment roughly is :Comparison: (11-19) to value assignment: 16.
I shall give some examples for better understanding. :
example 1 :
>12 56 98 12 76 34 97 23
>>(12 56) (98 12) (76 34) (97 23)
>>> 56 98 76 97
>>>> (56 98) (76 97)
>>>>> 98 97
>>>>>> 98
The largest element is 98
Now compare with lost ones of the largest element 98. 97 will be the second largest.
nlogn implementation
public class Test {
public static void main(String...args){
int arr[] = new int[]{1,2,2,3,3,4,9,5, 100 , 101, 1, 2, 1000, 102, 2,2,2};
System.out.println(getMax(arr, 0, 16));
}
public static Holder getMax(int[] arr, int start, int end){
if (start == end)
return new Holder(arr[start], Integer.MIN_VALUE);
else {
int mid = ( start + end ) / 2;
Holder l = getMax(arr, start, mid);
Holder r = getMax(arr, mid + 1, end);
if (l.compareTo(r) > 0 )
return new Holder(l.high(), r.high() > l.low() ? r.high() : l.low());
else
return new Holder(r.high(), l.high() > r.low() ? l.high(): r.low());
}
}
static class Holder implements Comparable<Holder> {
private int low, high;
public Holder(int r, int l){low = l; high = r;}
public String toString(){
return String.format("Max: %d, SecMax: %d", high, low);
}
public int compareTo(Holder data){
if (high == data.high)
return 0;
if (high > data.high)
return 1;
else
return -1;
}
public int high(){
return high;
}
public int low(){
return low;
}
}
}
Why not to use this hashing algorithm for given array[n]? It runs c*n, where c is constant time for check and hash. And it does n comparisons.
int first = 0;
int second = 0;
for(int i = 0; i < n; i++) {
if(array[i] > first) {
second = first;
first = array[i];
}
}
Or am I just do not understand the question...
In Python2.7: The following code works at O(nlog log n) for the extra sort. Any optimizations?
def secondLargest(testList):
secondList = []
# Iterate through the list
while(len(testList) > 1):
left = testList[0::2]
right = testList[1::2]
if (len(testList) % 2 == 1):
right.append(0)
myzip = zip(left,right)
mymax = [ max(list(val)) for val in myzip ]
myzip.sort()
secondMax = [x for x in myzip[-1] if x != max(mymax)][0]
if (secondMax != 0 ):
secondList.append(secondMax)
testList = mymax
return max(secondList)
public static int FindSecondLargest(int[] input)
{
Dictionary<int, List<int>> dictWinnerLoser = new Dictionary<int, List<int>>();//Keeps track of loosers with winners
List<int> lstWinners = null;
List<int> lstLoosers = null;
int winner = 0;
int looser = 0;
while (input.Count() > 1)//Runs till we get max in the array
{
lstWinners = new List<int>();//Keeps track of winners of each run, as we have to run with winners of each run till we get one winner
for (int i = 0; i < input.Count() - 1; i += 2)
{
if (input[i] > input[i + 1])
{
winner = input[i];
looser = input[i + 1];
}
else
{
winner = input[i + 1];
looser = input[i];
}
lstWinners.Add(winner);
if (!dictWinnerLoser.ContainsKey(winner))
{
lstLoosers = new List<int>();
lstLoosers.Add(looser);
dictWinnerLoser.Add(winner, lstLoosers);
}
else
{
lstLoosers = dictWinnerLoser[winner];
lstLoosers.Add(looser);
dictWinnerLoser[winner] = lstLoosers;
}
}
input = lstWinners.ToArray();//run the loop again with winners
}
List<int> loosersOfWinner = dictWinnerLoser[input[0]];//Gives all the elemetns who lost to max element of array, input array now has only one element which is actually the max of the array
winner = 0;
for (int i = 0; i < loosersOfWinner.Count(); i++)//Now max in the lossers of winner will give second largest
{
if (winner < loosersOfWinner[i])
{
winner = loosersOfWinner[i];
}
}
return winner;
}
Below is the problem description and algorithm that I have written. Is there anything to be done to improve this algorithm?
Given an integer array of unknown size, containing only numbers between 0 and 30, write a function to return an integer array containing all of the duplicates.
int[] findDupes(int[] array) {
int[] found = new int[30];
int[] dupes = new int[30];
int dupesCount = 0;
for (int i = 0; i < array.length; i++) {
if (found[array[i]] <= 1) {
found[array[i]]++;
}else{
continue;
}
if(found[array[i]] > 1){
dupes[dupesCount++] = array[i];
if (dupesCount == 30)
break;
}
}
if (dupesCount == 0)
return new int[0];
return dupes;
}
Am assuming that the best case for running this algorithm would n or 30 whichever is lower
and the worst case for running this algorithm is n, since I have to scan the entire array to find duplicates. Any comments?
You've got the right idea, but ask yourself, what does this block do, exactly
if(found[array[i]] > 1){
dupes[dupesCount++] = array[i];
if (dupesCount == 30)
break;
}
when does it fire?
Walk through your code with a couple of samples including an array of 1000 occurrences of 0.
What exactly are you returning? why do you need to special case 0.
Also the best case run time is going to be greater than 30. What is the minimum input that makes it stop before reaching the end?
Need more precise definition of the problem. Are there only 1 or 2 occurrences of an integer? Can there be 0 or 3 occurrences?
If there are only 1 or 2 occurrences of an integer, and integers range from 1 to 30; I would have a BitSet, and flip the bit as I find an integer. When I am done reading the original array, all the bits that are 0 will represent the integers containing duplicates.
Something strange:
if (found[array[i]] <= 1)
}else{
continue;//happens if found[array[i]] > 1
}
if(found[array[i]] > 1){//usually don't get here, because of continue
Is the continue a fix to only add a number once? Although it works, the code is misleading.
Do you have to return a 30 length array if there is only one duplicate?
I'd suggest making your code slower and better by splitting tasks.
here is the modified version with comments embedded.
int[] found = new int[3];
int[] dupes = new int[3];
int dupesCount = 0;
for (int i = 0; i < array.length; i++) {
if (found[array[i]] <= 1) {
found[array[i]]++;
}
if(found[array[i]] > 1){ //duplicate found
dupes[dupesCount++] = array[i];
// if 30 duplicate are found don't scan the array any more
// since the distinct numbers are only 30
if (dupesCount == 30)
break;
}
}
if (dupesCount == 0)
return null;
return dupes;