Even numbers before odd numbers using array and only one loop - java

I attempted the problem. I am not getting the right solution. Kindly help.
Problem : Return an array that contains the exact same numbers as the given array, but rearranged so that all the even numbers come before all the odd numbers. Other than that, the numbers can be in any order. You may modify and return the given array, or make a new array.
evenOdd([1, 0, 1, 0, 0, 1, 1]) → [0, 0, 0, 1, 1, 1, 1]
evenOdd([3, 3, 2]) → [2, 3, 3]
evenOdd([2, 2, 2]) → [2, 2, 2]
public int[] evenOdd(int[] nums) {
int l = nums.length;
if(l<2)
return nums;
int j=l-1;
for(int i=0;i<l;i++)
{
if(nums[i]%2==1)
{
while(j>i && nums[j]%2!=0) {
j--;
}
int t=nums[i];
nums[i]=nums[j];
nums[j]=t;
j--;
}
}
return nums;
}

As order of array doesn't matter and you need only one loop, you can try below function,
public int[] evenOdd(int[] nums) {
if (nums.length < 2) return nums;
int[] result = new int[nums.length];
int even = 0;
int odd = nums.length - 1;
for (int i = 0; i < nums.length; i++) {
if (nums[i] % 2 == 0)
result[even++] = nums[i];
else
result[odd--] = nums[i];
}
return result;
}

You're actually super close. If you just wrap this code that you have:
int t = nums[i];
nums[i] = nums[j];
nums[j] = t;
j--;
inside of an if
if (j > i)
your code actually works.

Not sure if this is "cheating", but you could create 2 arrays, 1 to hold the evens and 1 to hold the odds. In your loop, you would copy all the numbers of each value to their even or odd array, and then after the loop, join/merge the arrays together in a new array and return the new array.

If performance is not too important, you could use a stream:
static int[] evenOdd(int[] nums) {
return Arrays.stream(nums)
.boxed()
.sorted(Comparator.comparingInt(i -> i % 2))
.mapToInt(i -> i)
.toArray();
}
Unfortunately, IntStream doesn't have a sorted method that takes a Comparator (only a parameterless method, that's why you have to box and unbox to use Stream.sorted(Comparator).

Here is a code that takes O(N) time and O(1) space to accomplish your task. I apologise for the Python code.
arr = list(map(int, raw_input().split()))
i = 0
j = len(arr) - 1
while i<j:
if arr[i]%2 != 0 and arr[j]%2 == 0:
t = arr[i]
arr[i] = arr[j]
arr[j] = t
i = i + 1
j = j -1
elif arr[i]%2 == 0 and arr[j]%2 == 0:
i = i + 1
elif arr[i]%2 == 0 and arr[j]%2 != 0:
j = j - 1
else:
j = j - 1
print arr
Explanation: The code logic is quite self explanatory. We have two counters, i starting from left end and j starting from right end. If the left counter is pointing to an even then we just increment it, as it is in its correct place. [Remember you want to shift evens to the left. So this even is already in the left side of the array.So we just increment i]. Please look at the code logic to find out what actions are taken based on the current pointers on an even or an odd element.
For example:
If we find i pointing to an odd and j pointing to an `even, then we swap and move both pointers. This is understandable, I hope
The above solution is in-place and takes O(1) space and O(N) time... Hope this helps!!

Related

Complexity of following algorithm for the Three-Sum-Problem

Given is a sorted list (a[0],...,a[n-1]) of n integers. I need to find three different indices p, q, r such that the triplet (a[p],a[q],a[r]) satisfies the equation a[p]+a[q]+a[r]=0. Also, the sorted list can contain the same number more than once. The algorithm that is required needs to be quadratic.
I have found a solution (I'm definitely not saying that it is the most efficient one), but I'm quite sure that it's not quadratic (2 for-loops and a while-loop). Here is my code:
public ThreeSumIndices searchTriplet(List<Integer> list) {
for(int i=0; i<list.size()-1; i++){
int w = -list.get(i);
for(int j=i+1; j<list.size(); j++){
int k = 1;
while(j+k<list.size() && list.get(j)+list.get(j+k)!=w){
k++;
}
if(j+k==list.size()){
k = 1;
} else if(list.get(j)+list.get(j+k)==w){
return new ThreeSumIndices(i,j,j+k);
}
}
}
return null; //no indices found.
}
ThreeSumIndices is a seperate class. It returns the indices we're looking for in the form (p,q,r). Constructor parameters are three integer (= three indices).
Example: (-5, 1, 2, 3, 7) --> (0,2,3).
I'm fairly new to complexity analysis, so I was wondering whether my guess of this algorithm not being quadratic was correct or not.
If so, is there a way to get rid of a loop? Or maybe there's an alternative, but more efficient algorithm?
Thanks.
If the array is sorted then all you need to do is the following:
Run loop from i=0 to n-2.
Initialize two index variables l=i+1 and r=n-1
while:l<r, if ((sum = arr[i]+arr[l]+arr[r]) == 0):You got your answer
If sum is less than zero, increment l (l++), otherwise decrement r (r--)
scan all the elements.
for (int i=0; i < n-1; i++) {
int l = i + 1;
int r = n - 1;
int x = arr[i];
while (l < r){
if (x + arr[l] + arr[r] == 0) print()
else if(x + arr[l] + arr[r] < 0) l++;
else r--;
}
}
The time complexity of this code will be O(n^2) with space complexity of O(1)
I had to solve this for a coding interview, here's my python solution which has quadratic time complexity.
from collections import Counter
class Solution(object):
def threeSum(self, nums):
res = []
counts = Counter(nums)
num_counts = sorted(counts.items())
# If we pick 3 of the same nums
if counts[0] >= 3:
res.append([0] * 3)
for i, (first, first_count) in enumerate(num_counts):
# Pick two of these and one greater
if first_count >= 2 and first < 0 and -(first * 2) in counts:
res.append([first, first, -(first * 2)])
# Pick one and two greater
for j in range(i + 1, len(num_counts)):
second, second_count = num_counts[j]
# Pick two of these as second and third num
if second_count >= 2 and -first == 2 * second:
res.append([first, second, second])
# Pick this as second num and third which is greater
third = -(first + second)
if third > second and third in counts:
res.append([first, second, third])
return res
Basically, it counts the occurrences then sorts (number, count) tuples so that
[-1, 0, 1, 2, -1, -4]
becomes
[(-4, 1), (-1, 2), (0, 1), (1, 1), (2, 1)]
We then iterate trying to pick each number twice and third greater if possible and add that to the result. Then, we pick a number once and try to find two greater numbers which sum to zero.

in java I want to use for loop to pull out every number in odd position from integer array. what bug did I make?

So this is my method to pull out from a integer array(the length of this array is an even number).
public static int[] oddPosition (int[] array) {
int [] oddNumbers = new int[array.length / 2];
for (int i = 0; i < array.length; i++) {
int j = 0;
//System.out.println(i);//test
//printArray(oddNumbers); //test
if ((i + 1) % 2 != 0) {
//System.out.println(i);//test
oddNumbers[j] = array[i];
j ++;
}
}
return oddNumbers;
}
And it didn't work. I try to print out the situation inside my new array oddNumbers at every loop to debug this method. I used 1 2 8 4 6 9 as my parameter to this method.
I find a very strange condition is that when i = 0, (i + 1) % 2 != 0, then array[0](which is 1) should be assigned to oddNumbers[0]. and oddNumbers should be [1, 0, 0, 0] at first loop however the oddNumbers at first loop is 1, 0, 0, 2. Where is the 2 coming from...? The final result of this method I expected is 1, 8, 6 but it gives me 6, 0, 0. So what's wrong with my method? Thx!
How about, instead of looping through every index and then testing if it's odd, you start your loop at 1 and increase by 2 every time:
Example:
for(int i = 1; i < array.length; i+=2)
You should do it like #Conner G, but here, just to show your mistake so you don't do it again:
int j = 0;
is in the wrong place, you should put it before the loop, since it will be reset on every iteration, so you actually put every numbers on index = 0
It's a design issue as you should not step through each element in first place:
#Test
public void foo() {
int[] array = new int[]{1,2,3,4,5,6,7,8,9};
List<Integer> res = Lists.newArrayList();
for (int i = 0; i < array.length; i+=2) {
res.add(array[i]);
}
System.out.print(res);
}
[1, 3, 5, 7, 9]
Process finished with exit code 0

Counting Descending numbers?

I've been working on taking an array, lets say : {5,4,3,8,9,8,8,7,6} is my array. My goal is to find out how many sets of descending numbers there are in this array.
So far I've used my code to compare if the number in that index is less than the previous number. This is as far as I've gotten, and it prints out all the values that were smaller than the previous index value.
I'm semi new to java and have worked in python before, so I'm not quite sure how I would store the values that are less than the previous and how many total sets there are
public class Descending {
public static void main(final String[] args) {
int[] x = {5, 4, 3, 8, 9, 8, 8, 7, 6 };
countDescents(x);
}
public static void countDescents(final int[] xs) {
int total = 0;
// start with first index value.
// Compare to previous index value to see if it is descending.
for (int i = 1; i < xs.length; i++) {
if (xs[i] < xs[i - 1]) {
System.out.print(xs[i]);
}
}
}
}
In this example the total amount of descending sets would be 3 (desired output), those being 5,4,3 & 9,8 & 8,7,6
(The only reason my print statement is at that point in the loop is just to see if it was the right numbers as descending)
Given you don't need to know the length of the runs, just the number of them, then you are really just looking for how many times a run starts: i.e. an elements is one less than the previous but the same is not true for the previous element:
int runCount = 0;
boolean inRun = false;
for (int i = 1; i < array.length; i++) {
if (array[i] < array[i - 1] && !inRun)
runCount++;
inRun = array[i] < array[i - 1];
}
If you are using Java 8 you could do this with an IntStream instead of iteration:
int runCount = IntStream(1, array.length)
.filter(i -> array[i] < array[i - 1])
.filter(i -> i == 1 || array[i - 1] >= array[i - 2])
.count();
It's a bit unclear if you are looking to actually store the descending runs rather than just count them. If you need to know what the runs are then you will need to collect them in a list. Let me know in the comments if you want help with that.

Finding two non-subsequent elements in array which sum is minimal

Intro: As far as I could search, this question wasn't asked in SO yet.
This is an interview question.
I am not even specifically looking for a code solution, any algorithm/pseudocode will work.
The problem: Given an integer array int[] A and its size N, find 2 non-subsequent (can't be adjacent in the array) elements with minimal sum. Also the answer must not contain the first or last elements (index 0 and n-1). Also the solution should be in O(n) time and space complexity.
E.g. when A = [5, 2, 4, 6, 3, 7] the answer is 5, since 2+3=5.
When A = [1, 2, 3, 3, 2, 1] the answer is 4, since 2+2=4 and you can't choose either of the 1's since the are at the ends of the array.
Attempt: At first I thought that one of the numbers in the solution must be the smallest one in the array (besides the first and last), but this was refuted quickly with the counter-example A = [4, 2, 1, 2, 4] -> 4 (2+2)
Then I thought that if I find the 2 smallest numbers (besides the first and last) in the array, the solution will be those two. This obviously quickly failed because I can't choose 2 adjacent numbers, and if I have to choose non-adjacent numbers then this is the very definition of the question :).
Finally I thought, well, I will just find the 3 smallest numbers (besides the first and last) in the array, and the solution will have to be two of those, since two of those have to not be adjacent to each other.
This also failed due to A = [2, 2, 1, 2, 4, 2, 6] -> 2+1=3 , which seems to work because I will find 2, 1, 2, but assuming I am finding the 2, 1, 2 in indexes 1, 2, 3 this won't necessarily work (it would if I found specifically the 2 in index 5 but I can't guarantee that unfortunately).
Question:
Now I'm stumped, can anyone come up with a solution/idea that works?
Here is a live javascript implementation of an algorithm that:
finds the 4 smallest elements (excluding first/last element from search)
finds the pairs of these 4 elements that are not adjacent in original array
finds from these pairs the one with the minimal sum
function findMinNonAdjacentPair(a) {
var mins = [];
// quick exits:
if (a.length < 5) return {error: "no solution, too few elements."};
if (a.some(isNaN)) return {error: "non-numeric values given."};
// collect 4 smallest values by their indexes
for (var i = 1; i < a.length - 1; i++) { // O(n)
if (mins.length < 4 || a[i] < a[mins[3]]) {
// need to keep record of this element in sorted list of 4 elements
for (var j = Math.min(mins.length - 1, 2); j >= 0; j--) { // O(1)
if (a[i] >= a[mins[j]]) break;
mins[j+1] = mins[j];
}
mins[j+1] = i;
}
}
// mins now has the indexes to the 4 smallest values
// Find the smallest sum
var result = {
sum: a[mins[mins.length-1]]*2+1 // large enough
}
for (var j = 0; j < mins.length-1; j++) { // O(1)
for (var k = j + 1; k < mins.length; k++) {
if (Math.abs(mins[j] - mins[k]) > 1) { // not adjacent
if (result.sum > a[mins[j]]+a[mins[k]]) {
result.sum = a[mins[j]]+a[mins[k]];
result.index1 = mins[j];
result.index2 = mins[k];
};
if (k < j + 3) return result; // cannot be improved
break; // exit inner loop: it cannot bring improvement
}
}
}
return result;
}
// Get I/O elements
var input = document.getElementById('in');
var output = document.getElementById('out');
var select = document.getElementById('pre');
function process() {
// translate input to array of numbers
var a = input.value.split(',').map(Number);
// call main function and display returned value
output.textContent = JSON.stringify(findMinNonAdjacentPair(a), null, 4);
}
// respond to selection from list
select.onchange = function() {
input.value = select.value;
process();
}
// respond to change in input box
input.oninput = process;
// and produce result upon load:
process();
Type comma-separated list of values (or select one):</br>
<input id="in" value="2, 2, 1, 2, 4, 2, 6"> <=
<select id="pre">
<option value="5, 2, 4, 6, 3, 7">5, 2, 4, 6, 3, 7</option>
<option value="1, 2, 3, 3, 2, 1">1, 2, 3, 3, 2, 1</option>
<option value="4, 2, 1, 2, 4">4, 2, 1, 2, 4</option>
<option value="2, 2, 1, 2, 4, 2, 6" selected>2, 2, 1, 2, 4, 2, 6</option>
</select>
</br>
Output:</br>
<pre id="out"></pre>
The algorithm has a few loops with following big-O complexities:
find 4 smallest values: O(n), as the inner loop runs at most 3 times, which is O(1)
find the smallest sum of non-adjacent pairs has a double loop: in total the body will run at most 4 times = O(1). NB: The number of possible pairs is 6, but the execution is guaranteed to break out of the loops sooner.
So the algorithm runs in O(n).
Find the smallest number beside the first and the last.
Find the second smallest that is not a neighbour of the first one and not the first or last one in the array. Then build the sum.
If the first element is the second or the penultimate element you already have the solution.
Otherwise calculate the sum of both neighbours of the first number. check if its smaller then the first sum
if not: take the first sum
otherwise take the second one
This will always work because if the first sum is not the answer that means the first number cannot be part of the solution. And that on the other hand means, the solution can just be the second sum.
This problem can be solved with about 10 lines of Java code.
You can start with an obvious but inefficient (O(N^2)) solution:
public class Main {
int solve(int[] array) {
int answer = Integer.MAX_VALUE;
for (int i = 3; i < array.length - 1; i++) {
for (int j = 1; j < i - 1; j++) {
if (array[i] + array[j] < answer) {
answer = array[i] + array[j];
}
}
}
return answer;
}
}
But then you can notice that you actually do not need the internal for loop because you can just preserve the minimum and update it with every new element if necessary, which is faster than finding the minimum anew every time. Therefore the final O(N) solution looks like this:
public class Main {
int solve(int[] array) {
int answer = Integer.MAX_VALUE;
int min = array[1];
for (int i = 3; i < array.length - 1; i++) {
min = Math.min(min, array[i - 2]);
if (array[i] + min < answer) {
answer = array[i] + min;
}
}
return answer;
}
}
Find the four smallest and consider all possibilities among those four. The smallest is nonadjacent to at least one of the second, third, or fourth smallest; the only other possibility that could be better is the second and third smallest (assuming that they are nonadjacent).
I think this does not need any deep reasoning, and can be solved in a single pass, keeping the optimal solution of the array elements processed so far:
public static int[] minimumSumOfNonAcjacentElements(int[] a) {
// the result for the sequence a[1:i]
int minSum = Integer.MAX_VALUE;
int minSumElement1 = Integer.MAX_VALUE;
int minSumElement2 = Integer.MAX_VALUE;
// the minimum element eligible for joining with a[i], i.e. from a[1 : i-2]
int minElement = a[1];
int prevElement = a[2]; // a[i - 1]
for (int i = 3; i + 1 < a.length; i++) {
int sum = minElement + a[i];
if (sum < minSum) {
minSum = sum;
minSumElement1 = minElement;
minSumElement2 = a[i];
}
if (prevElement < minElement) {
minElement = prevElement;
}
prevElement = a[i];
}
return new int[] {minSumElement1, minSumElement2};
}
Here's some test code, with the corner cases from OP's question:
private static void test(int minSumIndex1, int minSumIndex2, int... input) {
int[] result = minimumSumOfNonAcjacentElements(input);
if (result[0] == minSumIndex1 && result[1] == minSumIndex2) {
// ok
} else {
throw new AssertionError("Expected: " + minSumIndex1 + ", " + minSumIndex2 + ". Actual=" + Arrays.toString(result));
}
}
public static void main(String[] args) throws Exception {
test(2, 2, 4, 2, 1, 2, 4);
test(1, 2, 2, 2, 1, 2, 4, 2, 6);
test(1, 2, 0, 2, 1, 2, 4, 2, 0);
System.out.println("All tests passed.");
}
Use dynamic programming.
Remove or disregard the first and last elements of your array. Since they cannot participate in the solution, they are not important. Once you've done this, you can also ignore the "must not be the first or last element" constraint since we've already accounted for it.
Find the solution for the first three elements of (what's left of) the array (and without considering the "no first/last element" rule). There is only one solution in this case (array[0] + array[2]), so this is a trivial step.
Memoize the minimal element which is not the last element (i.e. min(array[0], array[1])).
Find the solution for the first four elements. We don't have to redo the whole problem; instead we just have to ask whether introducing the fourth element allows us to produce a smaller solution. We can do this by adding the fourth element to the minimal element we memoized in the previous step, and comparing the sum to the solution we found in the second step.
Update the memoized minimal element so that it is the minimum of the first three elements.
Continue widening and updating in this fashion until we have considered the entire array.
The whole algorithm is O(n), since both widening and updating are constant-time operations. The algorithm can be proved correct by simple induction. O(n) is also a lower bound since we have to consider every element of the array, so this algorithm is optimal.
Algorithm:
Find the minimum, avoiding the end indices. (1 O(n) pass)
Find the minimum, avoiding the end indices and the index of (1) and adjacent indices. (1 O(n) pass)
Find the minimum, avoiding the end indices and the index of (1) (1 O(n) pass)
Find the minimum, avoiding the end indices and the index of (3) and adjacent indices. (1 O(n) pass)
Return the minimum of the sums (1) + (2), (3) + (4), if they exist.
Passes 3 and 4 are meant to pass the case [4, 2, 1, 2, 4] = 4 by finding both 2s.
public static int minSumNonAdjNonEnd(int[] array)
{
// 1. Find minimum
int minIdx1 = -1;
int minValue1 = Integer.MAX_VALUE;
for (int i = 1; i < array.length - 1; i++)
{
if (array[i] < minValue1)
{
minIdx1 = i;
minValue1 = array[i];
}
}
// 2. Find minimum not among (1) or adjacents.
int minIdx2 = -1;
int minValue2 = Integer.MAX_VALUE;
for (int i = 1; i < array.length - 1; i++)
{
if ((i < minIdx1 - 1 || i > minIdx1 + 1) && (array[i] < minValue2))
{
minIdx2 = i;
minValue2 = array[i];
}
}
boolean sum1Exists = (minIdx1 > -1 && minIdx2 > -1);
int sum1 = minValue1 + minValue2;
// 3. Find minimum not among (1).
int minIdx3 = -1;
int minValue3 = Integer.MAX_VALUE;
for (int i = 1; i < array.length - 1; i++)
{
if ((i != minIdx1) && (array[i] < minValue3))
{
minIdx3 = i;
minValue3 = array[i];
}
}
// 4. Find minimum not among(3) or adjacents.
int minIdx4 = -1;
int minValue4 = Integer.MAX_VALUE;
for (int i = 1; i < array.length - 1; i++)
{
if ((i < minIdx3 - 1 || i > minIdx3 + 1) && (array[i] < minValue4))
{
minIdx4 = i;
minValue4 = array[i];
}
}
boolean sum2Exists = (minIdx3 > -1 && minIdx4 > -1);
int sum2 = minValue3 + minValue4;
if (sum1Exists)
{
if (sum2Exists)
return Math.min(sum1, sum2);
else
return sum1;
}
else
{
if (sum2Exists)
return sum2;
else
throw new IllegalArgumentException("impossible");
}
}
This performs 4 linear searches, for a complexity of O(n).
Test cases:
System.out.println(minSumNonAdjNonEnd(new int[] {5, 2, 4, 6, 3, 7}));
System.out.println(minSumNonAdjNonEnd(new int[] {1, 2, 3, 3, 2, 1}));
System.out.println(minSumNonAdjNonEnd(new int[] {4, 2, 1, 2, 4}));
System.out.println(minSumNonAdjNonEnd(new int[] {2, 2, 1, 2, 4, 2, 6}));
System.out.println(minSumNonAdjNonEnd(new int[] {2, 2, 3, 2}));
5
4
4
3
Exception in thread "main" java.lang.IllegalArgumentException: impossible
I don't know if my solution is correct because I just tested it with the data in the OP, and I don't even know if this is better or worse than the other ideas but I wanted to try it.
static void printMinimalSum(int[] A) {
// Looking for mins so we init this with max value
int[] mins = new int[]{Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE};
// Indices, used just to print the solution
int[] indices = new int[]{-1, -1, -1};
// If the array has length 5 then there's only one solution with the 2nd and 4th elements
if (A.length == 5) {
mins[0] = A[1];
indices[0] = 1;
mins[1] = A[3];
indices[1] = 3;
} else {
// Loop on the array without considering the first and the last element
for (int i = 1; i < A.length - 1; i++) {
// We consider each element which is smaller than its neighbours
if ((i == 1 && A[i] < A[i + 1]) // 1: first element, compare it with the second one
|| (i == A.length - 2 && A[i] < A[i - 1]) // 2: last element, compare it with the previous one
|| (A[i] < A[i + 1] && A[i] < A[i - 1])) { // 3: mid element, compare it with both neighbors
// If the element is "legal" then we see if it's smaller than the 3 already saved
if (A[i] < mins[0]) {
mins[0] = A[i];
indices[0] = i;
} else if (A[i] < mins[1]) {
mins[1] = A[i];
indices[1] = i;
} else if (A[i] < mins[2]) {
mins[2] = A[i];
indices[2] = i;
}
}
}
}
// Compute the 3 sums between those 3 elements
int[] sums = new int[]{Math.abs(mins[0]+mins[1]), Math.abs(mins[0]+mins[2]), Math.abs(mins[1]+mins[2])};
// Find the smaller sum and print it
if (sums[0] < sums[1] || sums[0] < sums[2]){
System.out.println("Sum = " + sums[0] + " (elements = {" + mins[0] + "," + mins[1] + "}, indices = {" + indices[0] + "," + indices[1] + "}");
} else if (sums[1] < sums[0] || sums[1] < sums[2]){
System.out.println("Sum = " + sums[1] + " (elements = {" + mins[0] + "," + mins[2] + "}, indices = {" + indices[0] + "," + indices[2] + "}");
} else {
System.out.println("Sum = " + sums[2] + " (elements = {" + mins[1] + "," + mins[2] + "}, indices = {" + indices[1] + "," + indices[2] + "}");
}
}
public static void main(String[] args) {
printMinimalSum(new int[]{5, 2, 4, 6, 3, 7});
printMinimalSum(new int[]{1, 2, 3, 3, 2, 1});
printMinimalSum(new int[]{4, 2, 1, 2, 4});
printMinimalSum(new int[]{2, 2, 1, 2, 4, 2, 6});
}
Output is:
Sum = 5 (elements = {2,3}, indices = {1,4}
Sum = 4 (elements = {2,2}, indices = {1,4}
Sum = 4 (elements = {2,2}, indices = {1,3}
Sum = 3 (elements = {1,2}, indices = {2,5}
which seems fine.
edit: you're right, I completely ignored the adjacency constraint.
luckily I've thought of a solution.
The algorithm goes like this:
You run once over the array to find the smallest (O(n))
You run a second time to find the second smallest (O(n))
If second smallest is not adjacent to smallest we're done(O(1) - just an index check)
Otherwise run a third time to find third smallest (still O(n))
If not adjacent to smallest return smallest and third smallest
otherwise return second and third smallest
Elaborating on the above answer, you'd need a modified insertion-sort to track the smallest four values and the corresponding indexes (an array of 4 elements for each).
Once found the solution would be the first pair whose difference in indexes would be more than 1 and whose sum is the least.
The solution being one of (0,1) or (0,2) or (0,3) or (1,2) or (1,3) or (2,3) where the values indicate the indexes of the array that in turn tracks the position of the actual elements in the array.
Also you'd need to handle the special case for array-length 5 (arr\[1]+arr[3]) and an error for those arrays less than 5.
I think this should work:
Find the minimum 3 element and their indices. Since all of them can't be adjacent choose 2 among them.
If all of them are adjacent and the minimum number is in the middle of them, iterate through all elements, find the forth minimum element, choose minimum of min1+min4, min2+min3, whichever is smaller.
You can do this in one iteration too.
I have used dynamic programming to solve it.
Idea is to first create the array which tracks the minimum found till now as below:
Input array = [1, 3, 0, 5, 6]
Minimum array = [1, 1, 0, 0, 0]
Now using the minimum array and the input array we can use below:
DP[i] = min(DP[i-1], min(first_data, second_data))
where DP[i] means the minimum found till now which is sum of two previous alternate elements.
first_data = sum of current element in input array + sum of current-2 element in minimum array
second_data = sum of current-1 element in input array + sum of current-3 element in minimum array
import random
def get_min(numbers):
#disregard the first and last element
numbers = numbers[1:len(numbers)-1]
#for remembering the past results
DP = [0]*len(numbers)
#for keeping track of minimum till now found
table = [0]*len(numbers)
high_number = 1 << 30
min_number = numbers[0]
table[0] = min_number
for i in range(0, len(numbers)):
DP[i] = high_number
for i in range(1, len(numbers)):
if numbers[i] < min_number:
min_number = numbers[i]
table[i] = numbers[i]
else:
table[i] = min_number
for i in range(0, len(numbers)):
min_first, min_second = high_number, high_number
if i >= 2:
min_first = numbers[i] + table[i-2]
if i >= 3:
min_second = numbers[i-1] + table[i-3]
if i >= 1:
DP[i] = min(min(DP[i-1], min_first), min_second)
return DP[len(numbers)-1]
input = random.sample(range(100), 10)
print(input)
print(get_min(input))
How about that: you find k smallest numbers (or more precisely their indices) (k big enough, let say 10). It is sure, that the wanted pair is between them. Now you just check the possible 50 pairs and select the best which satisfies the constraints.
You don't need 10, less would do - but more than 3 :)
Edit: finding k smallest numbers is O(n), because you just keep the best 10 for example in a heap (add new element, delete maximum O(k*logk)=O(1) operations).
Then there will be a pair which satisfy the constraints (not next to each other). It is also clear that, if you build the sum with an element not from those k, it would be bigger than the best pair chosen from those k elements.
Checking at most k*k pairs is also O(1), thus the whole running time is O(n).
Here is the python implementation in O(N) time complexity
import math
def minSum(array):
_min = array[1]
result = math.inf
for i in range(3, len(array) - 1):
_min = min(_min, array[i-2])
if (_min + array[i]) < result:
result = _min + array[i]
return result
As we only need to track the minimum sum of two no adjacent values, we could do it by iterating over the array excluding the first and last element and keeping the track of min values and minimum sum. current min value will the two index before current value. For example if we are checking the current index i then minValue is the minimum value from index 1 to i-2.
Code:
int minSum(int[] A){
int minSum=Integer.MAX_VALUE;
int min= Integer.MAX_VALUE;
for(int i=3; i<A.length-1; i++){
min= Math.min(A[i-2], min);
minSum = Math.min(min+A[i], minSum);
}
return minSum;
}

Else if statements

I'm a beginner to java... if statements followed by else if statements are evaluated in order until one that evaluates to true is found, and I've seen many examples of this. But in this program, both statements (the if and the else if) are evaluated. Why?
public int centeredAverage(int[] nums) {
int[] nums = {1, 1, 5, 5, 10, 8, 7};
int sum = 0;
int centered = 0;
int min = nums[0];
int max = nums[0];
int i = 0;
for (i = 0; i < nums.length; i++){
if (nums[i] < min){
min = nums[i];
} else if (nums[i] > max){
max = nums[i];
}
sum += nums[i];
centered = ((sum-max-min)/(nums.length-2));
}
return centered;
}
Because they're in a loop that changes i and so changes nums[i] and so changes what if's are true.
Your passing in array of doubles by reference called nums and the defining an array of the same name in the method which seems odd. Also your start index for your for loop should be 1
Im guessing this is the same problem from codingbat, next time copy and paste the problem desciption for others!
public int centeredAverage(int[] nums) {
Arrays.sort(nums); //sorts the array smallest to biggest
int total = 0;
//nums is already sorted, so the smallest value is at spot 0
//and the biggest value is at the end.
for(int a = 1; a < nums.length - 1; a++){ //avoid the first and last numbers
total += nums[a];
}
return total / (nums.length - 2); //need ( ) so we can substract 2 first
//Another way could simply sum all the elements then subtract from that sum
//the biggest and smallest numbers in the array, then divide by nums.length- 2, it is a
//little more complex, but allows a for : each loop.
}
But for you, well since you are a beginner, restate your strategy (algorithm), find the smallest and biggest numbers in the array, subtract that out of the sum of all elements in the array then divide that number by nums.length - 2, since we are ignoring 2 numbers.
Working of If statement followed by else-if is fine here. We are getting expected result here. Both the statements if and else-if are not executed. Only that statement is executed which comes TRUE as per logic.
Here we can identify the working of the program using "System.out.println". Code and console output is given below...
int[] nums = {1, 1, 5, 5, 10, 8, 7};
int sum = 0;
int centered = 0;
int min = nums[0];
int max = nums[0];
int i = 0;
for (i = 0; i < nums.length; i++)
{
if (nums[i] > min)
{
min = nums[i];
System.out.println("inside first if: " + i);
// taking value of i in SOP to get the iteration value
}
else if (nums[i] > max)
{
max = nums[i];
}
sum += nums[i];
centered = ((sum-max-min)/(nums.length-2));
System.out.println("inside else if: " + i);
// taking value of i in SOP to get the iteration value
}
System.out.println("centered value "
+ " " + centered);
You can make a good usage of SOP in every program to get the execution order.

Categories