Find k-th element of an array - javascript

i am trying to figure out how this code works.
function Kth_greatest_in_array(arr, k) {
for (let i = 0; i < k; i++) {
let max_index = i;
const tmp = arr[i];
for (let j = i + 1; j < arr.length; j++) {
if (arr[j] > arr[max_index]) {
max_index = j;
}
}
arr[i] = arr[max_index];
arr[max_index] = tmp;
}
return arr[k - 1];
}
console.log(Kth_greatest_in_array([1,2,6,4,5], 3))
As you can see the goal is to find third biggest value. But i don know how the second loop works. Could you explain it to me step by step. For example, what is the meaning of veriable j, especially why they typed let j = i +

This method basically performs an in-place sort of the arr array (but only "k" times - not a full sort), then returns the element (from the now partially sorted array) at index k-1.
The inner for loop looks through the remaining (unsorted) portion of the array to find the index of the item with the highest value:
if (arr[j] > arr[max_index]) {
max_index = j;
}
The specific statement you were asking about, let j = i + 1, means "declare a new variable, j, and set its initial value to one greater than the current iteration of the outer for loop". "j" is arbitrary and could be any valid identifier, it's just often used by convention when you have nested for loops since the outermost loop usually uses i (which is presumably short for "index").
At the end of each iteration of the outer for loop, these lines swap array elements so that this element is in the correct position:
arr[i] = arr[max_index];
arr[max_index] = tmp;
If you're curious to really understand the inner workings of a method like this, I'd highly encourage you to step through it with a debugger - it can be a great learning experience. Even just the tried-and-true method of sprinkling some temporary console.log statements can help illuminate what's going on (e.g., print the state of arr and max_index after every outer and inner loop iteration).

Related

Pairwise sums challenge

I've got working code, but I'm looking to improve the way I understand and implement different coding techniques as a whole. I thought this problem presented a good chance to get feedback on what I'm doing.
The idea here is to take two arguments, an array and an integer. Identify all pairs in the array that sum to make the integer argument, and then return the sum of the indices. You cannot reuse an index, and you must always use the smallest index available to you. There is an explanation on the FCC code guide here: https://www.freecodecamp.org/learn/coding-interview-prep/algorithms/pairwise
So - here is the question. Is there any good way of doing this without using nested for loops? I am becoming increasingly aware of time/space complexities, and I know that O(n^2) won't land me the job.
I would imagine a hashmap of some sort would come into it, but I just don't have the experience and knowledge to know how to use them.
Here is the code:
function pairwise(arr, arg) {
let usedIndex = [];
let output = 0;
for (let i = 0; i < arr.length; i++) {
for (let j = i + 1; j < arr.length; j++) {
if (
arr[i] + arr[j] == arg
&& usedIndex.indexOf(i) == -1
&& usedIndex.indexOf(j) == -1
) {
usedIndex.push(i, j)
output += i + j
}
}
}
return output;
}
pairwise([0, 0, 0, 0, 1, 1], 1) // should return 10
This can be done in one loop with some clever use of an object and knowledge that indices can only be used once.
function pairwise(arr, arg) {
let map = {};
let output = 0;
let length = arr.length;
for (let i = 0; i < length; i++) {
let subArr = map[arr[i]];
if(subArr && subArr[0] !== undefined) {
//there is an index waiting to pair, remove it and add to output
output += subArr.pop() + i;
} else {
//add this index to its pair slot
let left = arg - arr[i];
if(!map[left]) map[left] = [];
map[left].unshift(i);
}
}
return output;
}
console.log(pairwise([0, 0, 0, 0, 1, 1], 1), "should be 10");
console.log(pairwise([1, 4, 2, 3, 0, 5], 7), "should be 11");
console.log(pairwise([], 100), "should be 0");
console.log(pairwise([1, 3, 2, 4], 4), "should be 1");
The keys of the map represent the other value needed to make a pair, and the values of the map are arrays of indices that have the value that would make a pair. The indices are inserted using unshift() so that pop() returns the first one that was inserted - the smallest one.
Iterating from the front guarantees that the smallest pairs are found first, and the map guarantees that any later index will know exactly what the earliest index that could make a pair is.
For a better performance you can save the arr.length into a variable, then for loop won't count every single loop.
function pairwise(arr, arg) {
let usedIndex = [];
let output = 0;
let length = arr.length;
for (let i = 0; i < length; i++) {
for (let j = i + 1; j < length; j++) {
if (
arr[i] + arr[j] == arg
&& usedIndex.indexOf(i) == -1
&& usedIndex.indexOf(j) == -1
) {
usedIndex.push(i, j)
output += i + j
}
}
}
return output;
}
Sort the list.
Have two counters walking from the ends. At each step check to see if the sum is what you want. If so, capture the desired metric.
Step 1 is O(n*logn).
Step 2 is O(n) -- each counter will go about halfway through the list, stopping when they meet.

Insertion Sort loop invariant

function insertionSort(arr) {
var length = arr.length,
val,
i,
j;
for(i = 0; i < length; i++) {
value = arr[i];
for(j = i - 1; j > -1 && arr[j] > value; j--) {
arr[j+1] = arr[j]
}
arr[j+1] = value;
}
return arr;
}
console.log(insertionSort([6,1,23,4,2,3]))
I am looking at an example of the insertion sort algorithm encoded in javascript, and having trouble understanding why it passes the conditional of the inner for loop. To be clear, this algorithm is correct -- I'm just having difficulty understanding why.
If j is initialized with i - 1, then the value of j is -1, since i is initialized at 0. In the first part of the conditional it states j > -1, which means it won't pass the this test, since j is not greater than -1.
Can someone tell me what I am missing?
You're right, the first iteration will not enter the second loop, but this is okay. Notice what that loop is doing. It's swapping array[j+1] with array[j]. When i == 0, then j == -1. You can't swap array[0] with array[-1], since it doesn't exist. This is a clever way of bypassing that issue.
However, this only happens on the first iteration. Subsequent iterations will enter the loop as expected.

Three Number Sum - Finding triplets that sum to target

Write a function that takes in a non-empty array of distinct integers and a target integer.
Your function should find all triplets in the array that sum up to the target sum and return a two-dimensional array of all these triplets.
Each inner array containing a single triplet should have all three of its elements ordered in ascending order
ATTEMPT
function threeNumberSum(arr, target) {
let results = [];
for (let i = 0; i < arr.length; i++) {
let finalT = target - arr[i];
let map = {};
for (let j = i+1; j < arr.length; j++) {
if (map[arr[j]]) {
results.push([arr[j], arr[i], map[arr[j]]]);
} else {
map[finalT-arr[j]] = arr[j];
}
}
}
return results;
}
My code is formatted all funny, but right now im not getting any output. Am I missing a console log somewhere or something?
Your problem is that you read input wrong.
Pay attention to the last part of question: How to Read Input that is Used to Test Your Implementation
You wrote a function that takes the array as first arg and the target integer as the second one. But the input is entered one by one, so your program should read one value at a time from the console input.

javascript choices for looping over select options

Recently I stole some javascript to select an option in a select element:
var el=document.getElementById('mySelect');
var opts=el.options;
for (var opt, j = 0; opt = opts[j]; j++) {
if (opt.value == 'Apple') {
el.selectedIndex = j;
break;
}
}
It works fine, but as I looked at it I realized it was different from what I would have written:
var el=document.getElementById('mySelect');
for (var j = 0; j < el.options.length; j++) {
if (el.options[j].value == 'Apple') {
el.selectedIndex = j;
break;
}
}
In looking at the first code, what stops the loop if 'Apple' is not found? Which one is 'better'?
In either case, the second expression determines if the loop should continue or stop. In yours,
for (var j = 0; j < el.options.length; j++) {}
it's straightforward, j will increment and as long as j is less than the options length it's true, and at some point it is equal to the length and then it stops. In the other one,
for (var opt, j = 0; opt = opts[j]; j++) {}
the difference is that they are declaring a variable opt and in the second expression set it to the (also incrementing) array index. At some point, j goes beyond the bounds of the array, and opts[j] is undefined. And since an equality expression in JS is the value of the right site, that expression is also undefined, which is falsy, and the loop stops.
As for which is better? Both work. But as you had to scratch your head and wonder about one of them, how much do you want to depend on code that's more difficult to read?
Long story short:
In your for loop var opt is executed once after which you have subsequent opt = data[i].
This is important because:
var opt, data = [1, 2]; // defined once
console.log(opt = data[0]) // 1
console.log(opt = data[1]) // 2
console.log(opt = data[2]) // undefined
When the for loop condition evaluates to falsy it will halt.
So in your case it does stop when opt = data[i] ends up being a falsy value - undefined
Which is at the point of i being 5 and data[i] becoming undefined and being assigned to opt ... which returns as a final result undefined.
You should also consider using this (if ES6 is an option):
var el=document.getElementById('mySelect');
el.selectedIndex = el.options.findIndex(x => x.value === 'Apple')
It is shorted and easier to read :).

Why this reverse function isn't working?

Why isn't this working?
ps. I don't want to use any other variable to make it work, and i don't want to use built in functions, just asking why THIS is not working?
function reverse(arr){
for(var i =0; i< arr.length; i++){
arr.push(arr[arr.length-i]);
}
return arr;
}
There are a lot of flaws in your code.
When you start pushing arr.push(arr[arr.length-i]); the array length increases, thereby, you won't get a consistency in the data.
This goes inside an infinite loop, as every time, the arr is ahead of its length.
It is better to use another variable and reverse, or you can use the built-in reverse() function. There's nothing wrong in having another variable and add temporary contents in it.
Solutions:
Using a temporary array:
function reverse(arr) {
var final = [];
for (var i = arr.length - 1; i >= 0; i--) {
final.push(arr[i]);
}
return final;
}
Using built-in function (Array.prototype.reverse()):
function reverse(arr) {
return arr.reverse();
}
Using few temporary variables:
a = [5,4,3,2,1];
function reverse(arr) {
var i = 0, j = arr.length - 1;
for (i = 0; i < j; i++, j--) {
var temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
return arr;
}
console.log(reverse(a));
You're going to run out of memory. What you're doing is adding what was initially the last element of that array infinitely to the end of your array. Every time that you call arr.push(...) you increase arr.length by one. Your for loop will never be able to finish because i will never be less than arr.length
I don't want to use any other variable to make it work, and i don't want to use built in functions
You cannot.
Use temporary array for result
function reverse(arr) {
var res = []
for (var i = arr.length - 1; i > -1; i--) {
res.push(arr[i]);
}
return res;
}

Categories

Resources