Related
I want to find the length smallest subarray whose sum is equal to k.
Input: arr[] = {2, 4, 6, 10, 2, 1}, K = 12
Output: 2
Explanation:
All possible subarrays with sum 12 are {2, 4, 6} and {10, 2}.
Input: arr[] = { 1, 2, 4, 3, 2, 4, 1 }, K = 7
Output: 2
Here's a solution using JavaScript.
It could be made more efficient, for sure, but I've coded it to work.
function lengthOfShortestSubArrayOfSumK(array, k) {
var combos=[];
for(var i=0; i<Math.pow(2, array.length); i++) {
var bin=("0".repeat(array.length)+i.toString(2)).slice(-array.length).split("");
var ones=bin.reduce((count, digit)=>{count+=digit=="1";return count;},0);
var sum=bin.reduce((sum, digit, index)=>{sum+=digit=="1"?array[index]:0;return sum;},0);
combos.push([bin, ones, sum]);
};
return combos.filter(combo=>combo[2]==k).sort((a, b)=>a[1]-b[1])[0][1];
}
var arraysAndKs=[
{array:[2, 4, 6, 10, 2, 1], k:12},
{array:[1, 2, 4, 3, 2, 4, 1], k:7}
];
for(arrayAndK of arraysAndKs)
console.log("Length of shortest sub array of ["+arrayAndK.array.join(", ")+"] with sum "+arrayAndK.k+" is : "+lengthOfShortestSubArrayOfSumK(arrayAndK.array, arrayAndK.k));
The Binary number between 0 and array.length squared will give us a representation of included array items in the sum.
We count how many "ones" are in that Binary number.
We sum array items masked by those "one"s.
We save into combos array an array of the Binary number, "one"s count, and sum.
We filter combos for sum k, sort by count of "one"s, and retrun the first's "one"s count.
I'm sure this can be translated to any programming language.
You can use an algorithm that finds a subset in size K, and save another variable that stores the number of members that make up such a subarray.
The algorithm for finding a K subarray is:
initialize an array of size K, Each place (idx) indicates whether there is a subarray that amounts to idx (I used a dictionary)
Go over any number (i) in the array, and any sum (j) we can reach in the previous iteration now we can reach j + i.
If in the K place it is marked TRUE, then there is a subarray that amounts to K.
Here's the solution in Python
def foo(arr,k):
dynamic = {0:0}
for i in arr:
temp = {}
for j, l in dynamic.items():
if i + j <= k: # if not it's not interesting us
# choose the smallest subarray
temp[i+j] = min(l+1,dynamic.get(i+j,len(arr)))
dynamic.update(temp)
return dynamic.get(k,-1)
the complexity is O(N*K).
I assumed that the subarray refers to any possible combinations of original array.
Here is a Python code that solves the problem under the condition that the subset must be contiguous:
in O(N) complexity
def shortest_contiguous_subarray(arr,k):
if k in arr:
return 1
n = len(arr)
sub_length = float('inf')
sub = arr[(i:=0)]
j = 1
while j < n:
while sub < k and j < n:
sub += arr[j]
j += 1
while sub > k:
sub -= arr[i]
i += 1
if sub == k:
# print(arr[i:j],j-i)
sub_length = min(sub_length,j-i)
sub -= arr[i]
i += 1
return sub_length if sub_length <= n else -1
This answer works for any array of positive numbers, and can be modified to work with arrays that have zero or negative elements if an O(n) pre-processing pass is performed (1. find the minimum element m, m <= 0, 2. make the whole array positive by adding -m+1 to all elements, 3. solve for sum + n*(1-m))
function search(input, goal) {
let queue = [ { avail: input.slice(), used: [], sum: 0 } ]; // initial state
for (let qi = 0; qi < queue.length; qi ++) {
let s = queue[qi]; // like a pop, but without using O(n) shift
for (let i = 0; i < s.avail.length; i++) {
let e = s.avail[i];
if (s.sum + e > goal) continue; // dead end
if (s.sum + e == goal) return [...s.used, e]; // eureka!!
queue.push({ // keep digging
avail: [...s.avail.slice(0, i), ...s.avail.slice(i+1)],
used: [...s.used, e],
sum: s.sum + e
});
}
}
return undefined; // no subset of input adds up to goal
}
console.log(search([2, 4, 6, 10, 2, 1], 12))
This is a classic breadth-first-search that does a little bit of pruning when it detects that we are already over the target sum. It can be further optimized to avoid exploring the same branch several times (for example, [4,2] is equivalent to [2,4]) - but this would require extra memory to keep a set of "visited" states. Additionally, you could add heuristics to explore more promising branches first.
I have done this by using unordered_map in c++. Hope this helps .
`
/* smallest subarray of sum k*/
#include<bits/stdc++.h>
using namespace std;
int main()
{
vector <int> v = {2,4,6,10,2,12};
int k=12;
unordered_map<int,int>m;
int start=0,end=-1;
int len=0,mini=INT_MAX;
int currsum=0;
for(int i=0;i<v.size();i++){
currsum+=v[i];
if(currsum==k){
start=0,end=i;
len=end-start+1;
mini=min(mini,len);
}
if(v[i]==k){
mini=min(mini,1);
}
if(m.find(currsum-k)!=m.end()){
end=i;
start=m[(currsum-k)]+1;
len=end-start+1;
mini=min(mini,len);
}
m[currsum]=i;
}
cout<<mini;
return 0;
}`
class Solution
{
static int findSubArraySum(int arr[], int N, int k)
{
// code here
// i use prefix sum and hashmap approach
HashMap<Integer, Integer> map = new HashMap<>();
map.put(0,1);
// this is bcoz when 1st element is valid one
int count=0;
int sum=0;
for(int i=0;i<N;i++){
sum += arr[i];
// prefix sum
if(map.containsKey(sum-k)){
count += map.get(sum-k);
}
map.put(sum, map.getOrDefault(sum,0)+1);
}
return count;
}
}
// this approach even for -ve numbers
// i came to dis solution by prefix sum approach
This version finds the entire optimal sub-array, not only its length. It's based on a recursion. It will test each number of the array against the optimal sub-array of the rest.
const bestSum = (targetSum, numbers) => {
var shortestCombination = null
for (var i = 0; i < numbers.length; i++) {
var current = numbers[i];
if (current == 0) {
continue
}
if (current == targetSum) {
return [current]
}
if (current > targetSum) {
continue;
}
// "remove" current from array
numbers[i] = 0;
// now the recursion:
var rest = bestSum(targetSum - current, numbers)
if (rest && (!shortestCombination || rest.length + 1 < shortestCombination.length)) {
shortestCombination = [current].concat(rest);
}
// restore current to array
numbers[i] = current
}
return shortestCombination
}
console.log(bestSum(7, [5, 3, 4, 7])) // Should be 7, not [3, 4]
This is my code in Python 3. I used the same idea of find the longest subarray with a sum equal to K. But in the below code for every prefix sum I am storing the recent index.
def smallestSubArraySumLength(a, n, k):
d=defaultdict(lambda:-1)
d[0]=-1
psum=0
maxl=float('inf')
for i in range(n):
psum+=a[I]
if psum-k in d:
maxl=min(maxl, i-d[psum-k])
d[psum]=i
return maxl
I I try to find the closest value in an array using binary search. Everything works fine as long as the value I am looking for is not smaller than the smallest value in the array.
Unfortunately, the debugger did not result in anything helpful. So I ask the community now. You can also try the code directly in the Xcode Playground. I tried to change an other searched value to a smaller value as in the array, but got the same error.
Error: error: Execution was interrupted, reason: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0).
func closestValue(_ arr: [Int],_ target: Int) -> Int {
var leftPointer = 0
var rightPointer = arr.count-1
while leftPointer < rightPointer {
let middleIndex = (leftPointer + rightPointer) / 2
let middleValue = arr[middleIndex]
if middleValue == target {
return middleValue
}
//Check for out of bounds error
let leftIndex = middleIndex-1
let leftValue = arr[leftIndex]
if leftValue <= target && middleValue >= target {
let leftDistance = abs(leftValue-target)
let rightDistance = abs(middleValue-target)
if leftDistance <= rightDistance {
return leftValue
} else {
return middleValue
}
}
if middleValue <= target {
leftPointer = middleIndex+1
} else {
rightPointer = middleIndex
}
}
guard let first = arr.first, let last = arr.last else {
fatalError()
}
if target <= first {
return first
} else if target >= last {
return last
} else {
fatalError()
}
}
let first = [1,2,3,5,5,5,7,9,19,11] // 6 --> 5
let second = [1,2,3] // 8 --> 3
let third = [9, 10, 22, 59, 67, 72, 100] // 70 --> 72
let fourth = [100, 101, 102] //5 --> 100 => Heres the error
print(closestValue(first, 6))
print(closestValue(second, 8))
print(closestValue(third, 110))
print(closestValue(fourth, 5))
I expected the fourth output 100. Because 100 is the closest value to 5 in the fourth array.
I can see you put in some boundary checks, but they should happen at the beginning of the function instead of the end. Allow me to rewrite the whole function:
func closestValue(_ arr: [Int],_ target: Int) -> Int {
// Array must not be empty
guard arr.count > 0 else { fatalError("Array must not be empty") }
// If array has only 1 element, that element is the closest
guard arr.count > 1 else { return arr[0] }
// To use binary search, your array must be ever-increasing or ever-decreasing
// Here, we require that the array must be ever-increasing
for index in 1..<arr.count {
if arr[index - 1] > arr[index] {
fatalError("Array must be monotonous increasing. Did you forget to sort it?")
}
}
// If the target is outside of the range of the array,
// return the edges of the array
guard arr.first! <= target else { return arr.first! }
guard target <= arr.last! else { return arr.last! }
// Now some actual searching
var left = 0
var right = arr.count - 1
while left < right {
if left == right - 1 {
return abs(arr[left] - target) <= abs(arr[right] - target) ? arr[left] : arr[right]
}
let middle = (left + right) / 2
switch arr[middle] {
case target:
return target
case ..<target:
left = middle
default:
right = middle
}
}
fatalError("It should never come here")
}
let first = [1,2,3,5,5,5,7,9,11,19] // 6 --> 5
let second = [1,2,3] // 8 --> 3
let third = [9, 10, 22, 59, 67, 72, 100] // 70 --> 72
let fourth = [100, 101, 102] //5 --> 100
print(closestValue(first, 6))
print(closestValue(second, 8))
print(closestValue(third, 70))
print(closestValue(fourth, 5))
Some notes:
if left == right - 1 { ... } allows the while loop to terminate. Otherwise, integer division will round middle down to `left, resulting in a infinite loop.
case ..<target is a short hand for "when arr[middle] < target"
The while should always find a solution and return from inside but I have not thoroughly tested that yet. If you find a case where it reaches the last fatalError, let me know.
The first example has two answers: both 5 and 7 are 1-away from target = 6.
I wonder why my solution to this LeetCode "Move Zeros" problem is slower than the majority of other submissions. Is there a better way to approach this problem to make it faster?
The question is as follows:
Given an array nums, write a function to move all 0's to the end of it while maintaining the relative order of the non-zero elements. You must do this in-place without making a copy of the array.
Example:
Input: [0,1,0,3,12]
Output: [1,3,12,0,0]
This is my solution:
func moveZeroes(_ nums: inout [Int]) {
var index = 0
for (i,n) in nums.enumerated()
{
if n != 0
{
nums[index] = n
index += 1
}
}
while index < nums.count
{
nums[index] = 0
index += 1
}
}
LeetCode gives me these statistics:
Runtime: 52 ms, faster than 40.50% of Swift online submissions for Move Zeroes.
Memory Usage: 19.4 MB, less than 13.33% of Swift online submissions for Move Zeroes.
EDIT 1:
If I approach the problem as follows, it does not move the zeros at the end,
EDIT 2:
Here is 36ms in-place solution for you :
class Solution {
func moveZeroes(_ nums: inout [Int]) {
if nums.count < 2 {
return
}
var j = 0
while j < nums.count, nums[j] != 0 {
j += 1
}
if j < nums.count - 1 {
for i in j+1..<nums.count {
if nums[i] != 0 {
nums.swapAt(i, j)
j += 1
}
}
}
}
}
From what I can see, it's likely other submissions are doing this
Check and count 0's in string
Remove 0's
Replace number of 0's at the end of the string
A logical method no doubt, but I'd say yours just picks the basic needs of the challenge and goes for it.
I would personally use:
input = input.filter { $0 != 0 } + input.filter { $0 == 0 }
which can be simplified to one pass:
let nonZeros = input.filter { $0 != 0 }
input = nonZeros + Array(repeating: 0, count: input.count - nonZeros.count)
EDIT: The simplest version without creating a new array would be some primitive version of bubble sort, e.g.:
var numZeros = 0
// iterate array from start to end
for (offset, element) in input.enumerated() {
if element == 0 {
// count every zero
numZeros += 1
} else if numZeros > 0 {
// move every non-zero element left
input[offset - numZeros] = element
// replace with zero
input[offset] = 0
}
}
Another approach is the half-stable-partition algorithm. The benefit is the items are swapped rather than removed and inserted/appended.
Half-stable means the order of the left side of the split point is preserved.
extension Array {
mutating func halfStablePartition(indexes : IndexSet) { // code is O(n)
guard var i = indexes.first, i < count else { return }
var j = index(after: i)
var k = indexes.integerGreaterThan(i) ?? endIndex
while j != endIndex {
if k != j { swapAt(i, j); formIndex(after: &i) }
else { k = indexes.integerGreaterThan(k) ?? endIndex }
formIndex(after: &j)
}
}
}
var input = [0,1,0,3,12]
let indices = IndexSet(input.indices.filter{input[$0] == 0})
input.halfStablePartition(indexes: indices)
Swift 4.2 or later using removeAll mutating method:
Mutating the input:
class Solution {
func moveZeroes(_ nums: inout [Int]) {
var counter = 0
nums.removeAll {
if $0 == 0 {
counter += 1
return true
}
return false
}
nums += repeatElement(0, count: counter)
}
}
A similar approach for Swift 4.1 or earlier
func moveZeroes(_ nums: inout [Int]) {
var counter = 0
nums.indices.reversed().forEach {
if nums[$0] == 0 {
counter += 1
nums.remove(at: $0)
}
}
nums += repeatElement(0, count: counter)
}
var input = [0,1,0,3,12]
moveZeroes(&input)
input // [1, 3, 12, 0, 0]
Non mutating approach:
func moveZeroes(_ nums: [Int]) -> [Int] {
var counter = 0
return nums.filter {
if $0 == 0 { counter += 1 }
return $0 != 0
} + repeatElement(0, count: counter)
}
let input = [0,1,0,3,12]
let zerosMoved = moveZeroes(input)
zerosMoved // [1, 3, 12, 0, 0]
For modifying array in place, and keeping it:
O(n) for Time Complexity
O(1) for Space Complexity
Cracked my head way to long for this one. The cleanest way if you swap element that is NOT zero:
func moveZeroes(_ nums: inout [Int]) {
// amount of swaps, will be used a as reference for next swap index
var j = 0
for (i, e) in nums.enumerated() {
if e != 0 {
nums.swapAt(j, i)
j += 1
}
}
}
One fast solution is to shift non-zero elements to the left by the amount of zeros encountered until then:
func moveZeroes(_ nums: inout [Int]) {
var offset = 0
for i in 0..<nums.count {
if nums[i] == 0 { offset += 1 }
else { nums.swapAt(i, i-offset) }
}
}
This solution takes exactly N steps, and at each step we either perform an addition, or a swap, which are both quite fast.
Your solution, on the other hand required two iterations, resulting in 2*N steps, which is why it was slower than other solutions.
My code won't run properly I am trying to get it to find peaks including the end and beginning of the array and then compare all the indexes that aren't the beginning or end to the index before and after them does anyone know why I am getting the out of index range error?
package main
import "fmt"
func linearFindPeaks(arg []int) []int {
peaks := []int{}
lenArg := len(arg)
for i := 0; i < lenArg; i++ {
//if its the first element run this
//second if statement for the end of array
// for default statements
if arg[0] > arg[1] {
peaks = append(peaks, arg[0])
} else if arg[lenArg-1] > arg[lenArg-2] {
peaks = append(peaks, arg[lenArg-1])
} else if arg[i] > arg[i+1] && arg[i] > arg[i-1] && arg[i] != arg[0] && arg[i] != arg[lenArg-1] {
peaks = append(peaks, arg[i])
}
}
fmt.Println(peaks)
return peaks
}
func main() {}
Playground: https://play.golang.org/p/2JRgEyRA50
Two possibilities i can see. Firstly, in the first else if:
}else if arg[lenArg - 1] > arg[lenArg -2] {
If lenArg is 1 then lenArg-2will be -1. This means arg[lenArg-2] is arg[-1] which will give you out of bounds.
Secondly, in the second else if:
} else if arg[i] > arg[i+1] ... {
On the last iteration over the loop, i will be lenArg-1, if you add 1 to this you'll get arg[lenArg-1+1] or arg[lenArg] which will out of bounds. (The last available index is at lenArg-1)
The Go Programming Language Specification
Index expressions
A primary expression of the form
a[x]
denotes the element of the slice a indexed by x.
The index x must be of integer type or untyped; it is in range if
0 <= x < len(a)
Otherwise it is out of range.
You need to pay attention to corner cases like lengths 0, 1, and 2 for indices i - 1, i, i + 1 out of range. For example,
package main
// For array a, a[i] is a peak if it is not smaller than its neighbor(s),
// where a[-1] = a[n] = -∞.
func findPeaks(a []int) []int {
var p []int
// special cases
if len(a) == 0 {
return p
}
if len(a) == 1 {
return append(p, a[0])
}
// first
i := 0
if a[i] >= a[i+1] {
p = append(p, a[i])
}
// first < i < last
for i = 1; i < len(a)-1; i++ {
if a[i-1] <= a[i] && a[i] >= a[i+1] {
p = append(p, a[i])
}
}
// last
i = len(a) - 1
if a[i-1] <= a[i] {
p = append(p, a[i])
}
return p
}
func main() {}
Playground: https://play.golang.org/p/9klj1wYnXZ
For an array of size N, what is the number of comparisons required?
The optimal algorithm uses n+log n-2 comparisons. Think of elements as competitors, and a tournament is going to rank them.
First, compare the elements, as in the tree
|
/ \
| |
/ \ / \
x x x x
this takes n-1 comparisons and each element is involved in comparison at most log n times. You will find the largest element as the winner.
The second largest element must have lost a match to the winner (he can't lose a match to a different element), so he's one of the log n elements the winner has played against. You can find which of them using log n - 1 comparisons.
The optimality is proved via adversary argument. See https://math.stackexchange.com/questions/1601 or http://compgeom.cs.uiuc.edu/~jeffe/teaching/497/02-selection.pdf or http://www.imada.sdu.dk/~jbj/DM19/lb06.pdf or https://www.utdallas.edu/~chandra/documents/6363/lbd.pdf
You can find the second largest value with at most 2·(N-1) comparisons and two variables that hold the largest and second largest value:
largest := numbers[0];
secondLargest := null
for i=1 to numbers.length-1 do
number := numbers[i];
if number > largest then
secondLargest := largest;
largest := number;
else
if number > secondLargest then
secondLargest := number;
end;
end;
end;
Use Bubble sort or Selection sort algorithm which sorts the array in descending order. Don't sort the array completely. Just two passes. First pass gives the largest element and second pass will give you the second largest element.
No. of comparisons for first pass: n-1
No. of comparisons for second pass: n-2
Total no. of comparison for finding second largest: 2n-3
May be you can generalize this algorithm. If you need the 3rd largest then you make 3 passes.
By above strategy you don't need any temporary variables as Bubble sort and Selection sort are in place sorting algorithms.
Here is some code that might not be optimal but at least actually finds the 2nd largest element:
if( val[ 0 ] > val[ 1 ] )
{
largest = val[ 0 ]
secondLargest = val[ 1 ];
}
else
{
largest = val[ 1 ]
secondLargest = val[ 0 ];
}
for( i = 2; i < N; ++i )
{
if( val[ i ] > secondLargest )
{
if( val[ i ] > largest )
{
secondLargest = largest;
largest = val[ i ];
}
else
{
secondLargest = val[ i ];
}
}
}
It needs at least N-1 comparisons if the largest 2 elements are at the beginning of the array and at most 2N-3 in the worst case (one of the first 2 elements is the smallest in the array).
case 1-->9 8 7 6 5 4 3 2 1
case 2--> 50 10 8 25 ........
case 3--> 50 50 10 8 25.........
case 4--> 50 50 10 8 50 25.......
public void second element()
{
int a[10],i,max1,max2;
max1=a[0],max2=a[1];
for(i=1;i<a.length();i++)
{
if(a[i]>max1)
{
max2=max1;
max1=a[i];
}
else if(a[i]>max2 &&a[i]!=max1)
max2=a[i];
else if(max1==max2)
max2=a[i];
}
}
Sorry, JS code...
Tested with the two inputs:
a = [55,11,66,77,72];
a = [ 0, 12, 13, 4, 5, 32, 8 ];
var first = Number.MIN_VALUE;
var second = Number.MIN_VALUE;
for (var i = -1, len = a.length; ++i < len;) {
var dist = a[i];
// get the largest 2
if (dist > first) {
second = first;
first = dist;
} else if (dist > second) { // && dist < first) { // this is actually not needed, I believe
second = dist;
}
}
console.log('largest, second largest',first,second);
largest, second largest 32 13
This should have a maximum of a.length*2 comparisons and only goes through the list once.
I know this is an old question, but here is my attempt at solving it, making use of the Tournament Algorithm. It is similar to the solution used by #sdcvvc , but I am using two-dimensional array to store elements.
To make things work, there are two assumptions:
1) number of elements in the array is the power of 2
2) there are no duplicates in the array
The whole process consists of two steps:
1. building a 2D array by comparing two by two elements. First row in the 2D array is gonna be the entire input array. Next row contains results of the comparisons of the previous row. We continue comparisons on the newly built array and keep building the 2D array until an array of only one element (the largest one) is reached.
2. we have a 2D-array where last row contains only one element: the largest one. We continue going from the bottom to the top, in each array finding the element that was "beaten" by the largest and comparing it to the current "second largest" value. To find the element beaten by the largest, and to avoid O(n) comparisons, we must store the index of the largest element in the previous row. That way we can easily check the adjacent elements. At any level (above root level),the adjacent elements are obtained as:
leftAdjacent = rootIndex*2
rightAdjacent = rootIndex*2+1,
where rootIndex is index of the largest(root) element at the previous level.
I know the question asks for C++, but here is my attempt at solving it in Java. (I've used lists instead of arrays, to avoid messy changing of the array size and/or unnecessary array size calculations)
public static Integer findSecondLargest(List<Integer> list) {
if (list == null) {
return null;
}
if (list.size() == 1) {
return list.get(0);
}
List<List<Integer>> structure = buildUpStructure(list);
System.out.println(structure);
return secondLargest(structure);
}
public static List<List<Integer>> buildUpStructure(List<Integer> list) {
List<List<Integer>> newList = new ArrayList<List<Integer>>();
List<Integer> tmpList = new ArrayList<Integer>(list);
newList.add(tmpList);
int n = list.size();
while (n>1) {
tmpList = new ArrayList<Integer>();
for (int i = 0; i<n; i=i+2) {
Integer i1 = list.get(i);
Integer i2 = list.get(i+1);
tmpList.add(Math.max(i1, i2));
}
n/= 2;
newList.add(tmpList);
list = tmpList;
}
return newList;
}
public static Integer secondLargest(List<List<Integer>> structure) {
int n = structure.size();
int rootIndex = 0;
Integer largest = structure.get(n-1).get(rootIndex);
List<Integer> tmpList = structure.get(n-2);
Integer secondLargest = Integer.MIN_VALUE;
Integer leftAdjacent = -1;
Integer rightAdjacent = -1;
for (int i = n-2; i>=0; i--) {
rootIndex*=2;
tmpList = structure.get(i);
leftAdjacent = tmpList.get(rootIndex);
rightAdjacent = tmpList.get(rootIndex+1);
if (leftAdjacent.equals(largest)) {
if (rightAdjacent > secondLargest) {
secondLargest = rightAdjacent;
}
}
if (rightAdjacent.equals(largest)) {
if (leftAdjacent > secondLargest) {
secondLargest = leftAdjacent;
}
rootIndex=rootIndex+1;
}
}
return secondLargest;
}
Suppose provided array is inPutArray = [1,2,5,8,7,3] expected O/P -> 7 (second largest)
take temp array
temp = [0,0], int dummmy=0;
for (no in inPutArray) {
if(temp[1]<no)
temp[1] = no
if(temp[0]<temp[1]){
dummmy = temp[0]
temp[0] = temp[1]
temp[1] = temp
}
}
print("Second largest no is %d",temp[1])
PHP version of the Gumbo algorithm: http://sandbox.onlinephpfunctions.com/code/51e1b05dac2e648fd13e0b60f44a2abe1e4a8689
$numbers = [10, 9, 2, 3, 4, 5, 6, 7];
$largest = $numbers[0];
$secondLargest = null;
for ($i=1; $i < count($numbers); $i++) {
$number = $numbers[$i];
if ($number > $largest) {
$secondLargest = $largest;
$largest = $number;
} else if ($number > $secondLargest) {
$secondLargest = $number;
}
}
echo "largest=$largest, secondLargest=$secondLargest";
Assuming space is irrelevant, this is the smallest I could get it. It requires 2*n comparisons in worst case, and n comparisons in best case:
arr = [ 0, 12, 13, 4, 5, 32, 8 ]
max = [ -1, -1 ]
for i in range(len(arr)):
if( arr[i] > max[0] ):
max.insert(0,arr[i])
elif( arr[i] > max[1] ):
max.insert(1,arr[i])
print max[1]
try this.
max1 = a[0].
max2.
for i = 0, until length:
if a[i] > max:
max2 = max1.
max1 = a[i].
#end IF
#end FOR
return min2.
it should work like a charm. low in complexity.
here is a java code.
int secondlLargestValue(int[] secondMax){
int max1 = secondMax[0]; // assign the first element of the array, no matter what, sorted or not.
int max2 = 0; // anything really work, but zero is just fundamental.
for(int n = 0; n < secondMax.length; n++){ // start at zero, end when larger than length, grow by 1.
if(secondMax[n] > max1){ // nth element of the array is larger than max1, if so.
max2 = max1; // largest in now second largest,
max1 = secondMax[n]; // and this nth element is now max.
}//end IF
}//end FOR
return max2;
}//end secondLargestValue()
Use counting sort and then find the second largest element, starting from index 0 towards the end. There should be at least 1 comparison, at most n-1 (when there's only one element!).
#include<stdio.h>
main()
{
int a[5] = {55,11,66,77,72};
int max,min,i;
int smax,smin;
max = min = a[0];
smax = smin = a[0];
for(i=0;i<=4;i++)
{
if(a[i]>max)
{
smax = max;
max = a[i];
}
if(max>a[i]&&smax<a[i])
{
smax = a[i];
}
}
printf("the first max element z %d\n",max);
printf("the second max element z %d\n",smax);
}
The accepted solution by sdcvvc in C++11.
#include <algorithm>
#include <iostream>
#include <vector>
#include <cassert>
#include <climits>
using std::vector;
using std::cout;
using std::endl;
using std::random_shuffle;
using std::min;
using std::max;
vector<int> create_tournament(const vector<int>& input) {
// make sure we have at least two elements, so the problem is interesting
if (input.size() <= 1) {
return input;
}
vector<int> result(2 * input.size() - 1, -1);
int i = 0;
for (const auto& el : input) {
result[input.size() - 1 + i] = el;
++i;
}
for (uint j = input.size() / 2; j > 0; j >>= 1) {
for (uint k = 0; k < 2 * j; k += 2) {
result[j - 1 + k / 2] = min(result[2 * j - 1 + k], result[2 * j + k]);
}
}
return result;
}
int second_smaller(const vector<int>& tournament) {
const auto& minimum = tournament[0];
int second = INT_MAX;
for (uint j = 0; j < tournament.size() / 2; ) {
if (tournament[2 * j + 1] == minimum) {
second = min(second, tournament[2 * j + 2]);
j = 2 * j + 1;
}
else {
second = min(second, tournament[2 * j + 1]);
j = 2 * j + 2;
}
}
return second;
}
void print_vector(const vector<int>& v) {
for (const auto& el : v) {
cout << el << " ";
}
cout << endl;
}
int main() {
vector<int> a;
for (int i = 1; i <= 2048; ++i)
a.push_back(i);
for (int i = 0; i < 1000; i++) {
random_shuffle(a.begin(), a.end());
const auto& v = create_tournament(a);
assert (second_smaller(v) == 2);
}
return 0;
}
I have gone through all the posts above but I am convinced that the implementation of the Tournament algorithm is the best approach. Let us consider the following algorithm posted by #Gumbo
largest := numbers[0];
secondLargest := null
for i=1 to numbers.length-1 do
number := numbers[i];
if number > largest then
secondLargest := largest;
largest := number;
else
if number > secondLargest then
secondLargest := number;
end;
end;
end;
It is very good in case we are going to find the second largest number in an array. It has (2n-1) number of comparisons. But what if you want to calculate the third largest number or some kth largest number. The above algorithm doesn't work. You got to another procedure.
So, I believe tournament algorithm approach is the best and here is the link for that.
The following solution would take 2(N-1) comparisons:
arr #array with 'n' elements
first=arr[0]
second=-999999 #large negative no
i=1
while i is less than length(arr):
if arr[i] greater than first:
second=first
first=arr[i]
else:
if arr[i] is greater than second and arr[i] less than first:
second=arr[i]
i=i+1
print second
It can be done in n + ceil(log n) - 2 comparison.
Solution:
it takes n-1 comparisons to get minimum.
But to get minimum we will build a tournament in which each element will be grouped in pairs. like a tennis tournament and winner of any round will go forward.
Height of this tree will be log n since we half at each round.
Idea to get second minimum is that it will be beaten by minimum candidate in one of previous round. So, we need to find minimum in potential candidates (beaten by minimum).
Potential candidates will be log n = height of tree
So, no. of comparison to find minimum using tournament tree is n-1
and for second minimum is log n -1
sums up = n + ceil(log n) - 2
Here is C++ code
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <vector>
using namespace std;
typedef pair<int,int> ii;
bool isPowerOfTwo (int x)
{
/* First x in the below expression is for the case when x is 0 */
return x && (!(x&(x-1)));
}
// modified
int log_2(unsigned int n) {
int bits = 0;
if (!isPowerOfTwo(n))
bits++;
if (n > 32767) {
n >>= 16;
bits += 16;
}
if (n > 127) {
n >>= 8;
bits += 8;
}
if (n > 7) {
n >>= 4;
bits += 4;
}
if (n > 1) {
n >>= 2;
bits += 2;
}
if (n > 0) {
bits++;
}
return bits;
}
int second_minima(int a[], unsigned int n) {
// build a tree of size of log2n in the form of 2d array
// 1st row represents all elements which fights for min
// candidate pairwise. winner of each pair moves to 2nd
// row and so on
int log_2n = log_2(n);
long comparison_count = 0;
// pair of ints : first element stores value and second
// stores index of its first row
ii **p = new ii*[log_2n];
int i, j, k;
for (i = 0, j = n; i < log_2n; i++) {
p[i] = new ii[j];
j = j&1 ? j/2+1 : j/2;
}
for (i = 0; i < n; i++)
p[0][i] = make_pair(a[i], i);
// find minima using pair wise fighting
for (i = 1, j = n; i < log_2n; i++) {
// for each pair
for (k = 0; k+1 < j; k += 2) {
// find its winner
if (++comparison_count && p[i-1][k].first < p[i-1][k+1].first) {
p[i][k/2].first = p[i-1][k].first;
p[i][k/2].second = p[i-1][k].second;
}
else {
p[i][k/2].first = p[i-1][k+1].first;
p[i][k/2].second = p[i-1][k+1].second;
}
}
// if no. of elements in row is odd the last element
// directly moves to next round (row)
if (j&1) {
p[i][j/2].first = p[i-1][j-1].first;
p[i][j/2].second = p[i-1][j-1].second;
}
j = j&1 ? j/2+1 : j/2;
}
int minima, second_minima;
int index;
minima = p[log_2n-1][0].first;
// initialize second minima by its final (last 2nd row)
// potential candidate with which its final took place
second_minima = minima == p[log_2n-2][0].first ? p[log_2n-2][1].first : p[log_2n-2][0].first;
// minima original index
index = p[log_2n-1][0].second;
for (i = 0, j = n; i <= log_2n - 3; i++) {
// if its last candidate in any round then there is
// no potential candidate
if (j&1 && index == j-1) {
index /= 2;
j = j/2+1;
continue;
}
// if minima index is odd, then it fighted with its index - 1
// else its index + 1
// this is a potential candidate for second minima, so check it
if (index&1) {
if (++comparison_count && second_minima > p[i][index-1].first)
second_minima = p[i][index-1].first;
}
else {
if (++comparison_count && second_minima > p[i][index+1].first)
second_minima = p[i][index+1].first;
}
index/=2;
j = j&1 ? j/2+1 : j/2;
}
printf("-------------------------------------------------------------------------------\n");
printf("Minimum : %d\n", minima);
printf("Second Minimum : %d\n", second_minima);
printf("comparison count : %ld\n", comparison_count);
printf("Least No. Of Comparisons (");
printf("n+ceil(log2_n)-2) : %d\n", (int)(n+ceil(log(n)/log(2))-2));
return 0;
}
int main()
{
unsigned int n;
scanf("%u", &n);
int a[n];
int i;
for (i = 0; i < n; i++)
scanf("%d", &a[i]);
second_minima(a,n);
return 0;
}
function findSecondLargeNumber(arr){
var fLargeNum = 0;
var sLargeNum = 0;
for(var i=0; i<arr.length; i++){
if(fLargeNum < arr[i]){
sLargeNum = fLargeNum;
fLargeNum = arr[i];
}else if(sLargeNum < arr[i]){
sLargeNum = arr[i];
}
}
return sLargeNum;
}
var myArray = [799, -85, 8, -1, 6, 4, 3, -2, -15, 0, 207, 75, 785, 122, 17];
Ref: http://www.ajaybadgujar.com/finding-second-largest-number-from-array-in-javascript/
A good way with O(1) time complexity would be to use a max-heap. Call the heapify twice and you have the answer.
int[] int_array = {4, 6, 2, 9, 1, 7, 4, 2, 9, 0, 3, 6, 1, 6, 8};
int largst=int_array[0];
int second=int_array[0];
for (int i=0; i<int_array.length; i++){
if(int_array[i]>largst) {
second=largst;
largst=int_array[i];
}
else if(int_array[i]>second && int_array[i]<largst) {
second=int_array[i];
}
}
I suppose, follow the "optimal algorithm uses n+log n-2 comparisons" from above, the code that I came up with that doesn't use binary tree to store the value would be the following:
During each recursive call, the array size is cut in half.
So the number of comparison is:
1st iteration: n/2 comparisons
2nd iteration: n/4 comparisons
3rd iteration: n/8 comparisons
...
Up to log n iterations?
Hence, total => n - 1 comparisons?
function findSecondLargestInArray(array) {
let winner = [];
if (array.length === 2) {
if (array[0] < array[1]) {
return array[0];
} else {
return array[1];
}
}
for (let i = 1; i <= Math.floor(array.length / 2); i++) {
if (array[2 * i - 1] > array[2 * i - 2]) {
winner.push(array[2 * i - 1]);
} else {
winner.push(array[2 * i - 2]);
}
}
return findSecondLargestInArray(winner);
}
Assuming array contain 2^n number of numbers.
If there are 6 numbers, then 3 numbers will move to the next level, which is not right.
Need like 8 numbers => 4 number => 2 number => 1 number => 2^n number of number
package com.array.orderstatistics;
import java.util.Arrays;
import java.util.Collections;
public class SecondLargestElement {
/**
* Total Time Complexity will be n log n + O(1)
* #param str
*/
public static void main(String str[]) {
Integer[] integerArr = new Integer[] { 5, 1, 2, 6, 4 };
// Step1 : Time Complexity will be n log(n)
Arrays.sort(integerArr, Collections.reverseOrder());
// Step2 : Array.get Second largestElement
int secondLargestElement = integerArr[1];
System.out.println(secondLargestElement);
}
}
Sort the array into ascending order then assign a variable to the (n-1)th term.