Javascript To create a reverse sentence , what have I done wrong? [closed] - javascript

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 15 days ago.
Improve this question
to achieve
reverse("cool"); // "looc"
reverse("The quick brown fox jumps over the lazy dog") //"god yzal eht revo spmuj xof nworb kciuq ehT"
reverse("anna") // "anna"
My code is
function reverse(sentence) {
let reversedword = ""
for (let i = sentence.length; i < 0; i = i-1) {
reversedword = reversedword + sentence[i];
}
return reversedword;
}
console.log(
reverse("cool")
)
console.log(
reverse("The quick brown fox jumps over the lazy dog")
)
console.log(
reverse("anna")
)
The output of my code is empty "". Can someone help to fix my code so that I can understand?

You should start the loop with length-1, and have the condition to i>=0.
Explanation:
You want to initialize your counter with the last character of your string. For example hello has 5 characters.
And then the last character's index is 4 (Strings as arrays, are "zero-indexed"). So the first character (h) index is 0 and the last is 4.
That's why you would initialize your array with sentence.length-1.
Then, you want your loop to continue while your index (i) is positive, or equals 0 which means that you reached the first character of your string.
See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for#syntax
function reverse(sentence) {
let reversedword = ""
for (let i = sentence.length - 1; i >= 0; i = i - 1) {
reversedword = reversedword + sentence[i];
}
return reversedword;
}
console.log(reverse("cool"));

there are two things which needs to be corrected
The condition in for loop is wrong which says i<0, it should be i > 0, since we will stop when i becomes zero as this is reverse loop.
Second thing is accessing the index, sentence[i], i will be out of bound index as javascript array starts from index 0.
Please find below as the corrected and working code
function reverse(sentence) {
let reversedword = ""
for (let i = sentence.length; i > 0; i = i - 1) {
reversedword = reversedword + sentence[i - 1];
}
return reversedword;
}
console.log(
reverse("cool")
)
console.log(
reverse("The quick brown fox jumps over the lazy dog")
)
console.log(
reverse("anna")
)

Just fix the for loop you'll get the desired out
function reverse(sentence){
let reversedword = ""
for ( let i = sentence.length - 1 ; i >= 0 ; i = i-1 ){
reversedword = reversedword + sentence[i];
}
return reversedword;
}
console.log(reverse("cool")); // "looc"
console.log(reverse("The quick brown fox jumps over the lazy dog")) //"god yzal eht revo spmuj xof nworb kciuq ehT"
console.log(reverse("anna"));

Related

Count the capitals in the word javascript [duplicate]

This question already has answers here:
Counting upper and lower case characters in a string
(7 answers)
Closed last year.
) I am trying to solve one problem with this statement :
Write a function called howManyCaps which counts the capitals in the word,it then returns a sentence saying how which letters are capital and how many capitals there are in total.
This is my function
function howManyCaps(str) {
var count = 0;
for (i = 0; i < str.length; i++) {
if (str[i] == str[i].toUpperCase()) {
console.log(true);
count++;
} else {
false;
}
}
return count;
}
but in console if try with something like str=" How many Caps" y see a value of 5 instead of 2.
Any suggestions?
Thanks
The simplest way is [O(N)]:
function howManyCaps(str) {
let upper = 0;
for (let i = 0; i < str.length; i++) {
if (str[i] >= 'A' && str[i] <= 'Z') upper++;
}
return upper;
};
howManyCaps(' How many Caps');
Some people are saying don't use spaced or account for spaces, but that also is not a good strategy because it will also break for special characters.
Problem is your spacing.
" How many Caps"
has 3 spaces and 2 capital letters.. that should help you debug
If regular expressions are available to you, I would suggest the following:
function howManyCaps(str) {
return str.length - str.replace(/[A-Z]+/g, "").length;
}
var str = " How many Caps";
console.log("Input has " + howManyCaps(str) + " capital letters.");
The idea is to compare the length of the original input against the length of the input with all capital letters removed.
The better way is to use regex
Below is the code
function howManyCaps(str) {
return str.replace(/[^A-Z]/g, '').length;
}
console.log(howManyCaps(" How many Caps"))

Check similarity between strings in Javascript [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 1 year ago.
Improve this question
How to compare 2 text strings to see if they are similar, for example:
var a = "Hello Blue World";
var b = "Hello Blut World?";
if(a similar b)
{
console.log(true);
}
You could use string-similarity library.
Finds degree of similarity between strings, based on Dice's Coefficient, which is mostly better than Levenshtein distance.
var a = "Hello Blue World";
var b = "Hello Blut World?";
var stringSimilarity = require("string-similarity");
var similarityCoef = stringSimilarity.compareTwoStrings(a, b);
if (similarityCoef > 0.8) { console.log(true); }
Note that similarityCoef print true when the string matches at 80% (0.8). You can adjust this value to your needs.
That's tricky. Because you have somehow to tell in percent what similarity means for you. What about this approach?
You compare them string by string and count the matches. I know that this will fail as soon as there is one additional character very early in one of the strings. But for a start it should suffice.
var a = "Hello Blue World";
var b = "Hello Blut World?";
// only compare both strings with their mutual length, because of the loop we use
const mutualLength = (a.length > b.length) ? b.length : a.length;
const similarityAt = 90; // percent
let matchCount = 0;
// with each match increase matchCount by 1
for (let pointer = 0; pointer < mutualLength; pointer++) {
if (a.substring(pointer, 1) === (b.substring(pointer, 1) {
matchCount++;
}
}
// compute similarity in percent
const similarity = (matchCount * 100) / mutualLength;
console.log('Similarity given: ' + (similarity >= similarityAt));
B"H
Depends on degree of similarity, but if you want a percent amount to tell you what matches, you can simply loop through the shortest, and keep track of how many times each character matches with the subsequent index of the longest string (or add whitespace to the shortest string, but that might mess up some calculations), and then divide the total number of matches with the length of the (shortest) string to get the percent of equality
var str1 = "Hello blue world"
var str2 = "Hello blut world?!"
var shortest = str2.length >= str1.length?str1:str2
var longest = str2.length < str1.length?str1:str2
var matches= 0
shortest
.split("")
//Just check if index of shortest
//Matches index of longest, and if so (&& means do next
//Expression) add the total number of matches by one
.forEach (
(x,k)=>
((x==longest[k]) && (matches++) )
)
//Final result, divide matches by total length
var similarity = matches / shortest.length

How can I split a string into a given number of lines?

Here is my question:
Given a string, which is made up of space separated words, how can I split that into N strings of (roughly) even length, only breaking on spaces?
Here is what I've gathered from research:
I started by researching word-wrapping algorithms, because it seems to me that this is basically a word-wrapping problem. However, the majority of what I've found so far (and there is A LOT out there about word wrapping) assumes that the width of the line is a known input, and the number of lines is an output. I want the opposite.
I have found a (very) few questions, such as this that seem to be helpful. However, they are all focused on the problem as one of optimization - e.g. how can I split a sentence into a given number of lines, while minimizing the raggedness of the lines, or the wasted whitespace, or whatever, and do it in linear (or NlogN, or whatever) time. These questions seem mostly to be unanswered, as the optimization part of the problem is relatively "hard".
However, I don't care that much about optimization. As long as the lines are (in most cases) roughly even, I'm fine if the solution doesn't work in every single edge case, or can't be proven to be the least time complexity. I just need a real world solution that can take a string, and a number of lines (greater than 2), and give me back an array of strings that will usually look pretty even.
Here is what I've come up with:
I think I have a workable method for the case when N=3. I start by putting the first word on the first line, the last word on the last line, and then iteratively putting another word on the first and last lines, until my total width (measured by the length of the longest line) stops getting shorter. This usually works, but it gets tripped up if your longest words are in the middle of the line, and it doesn't seem very generalizable to more than 3 lines.
var getLongestHeaderLine = function(headerText) {
//Utility function definitions
var getLongest = function(arrayOfArrays) {
return arrayOfArrays.reduce(function(a, b) {
return a.length > b.length ? a : b;
});
};
var sumOfLengths = function(arrayOfArrays) {
return arrayOfArrays.reduce(function(a, b) {
return a + b.length + 1;
}, 0);
};
var getLongestLine = function(lines) {
return lines.reduce(function(a, b) {
return sumOfLengths(a) > sumOfLengths(b) ? a : b;
});
};
var getHeaderLength = function(lines) {
return sumOfLengths(getLongestLine(lines));
}
//first, deal with the degenerate cases
if (!headerText)
return headerText;
headerText = headerText.trim();
var headerWords = headerText.split(" ");
if (headerWords.length === 1)
return headerText;
if (headerWords.length === 2)
return getLongest(headerWords);
//If we have more than 2 words in the header,
//we need to split them into 3 lines
var firstLine = headerWords.splice(0, 1);
var lastLine = headerWords.splice(-1, 1);
var lines = [firstLine, headerWords, lastLine];
//The header length is the length of the longest
//line in the header. We will keep iterating
//until the header length stops getting shorter.
var headerLength = getHeaderLength(lines);
var lastHeaderLength = headerLength;
while (true) {
//Take the first word from the middle line,
//and add it to the first line
firstLine.push(headerWords.shift());
headerLength = getHeaderLength(lines);
if (headerLength > lastHeaderLength || headerWords.length === 0) {
//If we stopped getting shorter, undo
headerWords.unshift(firstLine.pop());
break;
}
//Take the last word from the middle line,
//and add it to the last line
lastHeaderLength = headerLength;
lastLine.unshift(headerWords.pop());
headerLength = getHeaderLength(lines);
if (headerLength > lastHeaderLength || headerWords.length === 0) {
//If we stopped getting shorter, undo
headerWords.push(lastLine.shift());
break;
}
lastHeaderLength = headerLength;
}
return getLongestLine(lines).join(" ");
};
debugger;
var header = "an apple a day keeps the doctor away";
var longestHeaderLine = getLongestHeaderLine(header);
debugger;
EDIT: I tagged javascript, because ultimately I would like a solution I can implement in that language. It's not super critical to the problem though, and I would take any solution that works.
EDIT#2: While performance is not what I'm most concerned about here, I do need to be able to perform whatever solution I come up with ~100-200 times, on strings that can be up to ~250 characters long. This would be done during a page load, so it needs to not take forever. For example, I've found that trying to offload this problem to the rendering engine by putting each string into a DIV and playing with the dimensions doesn't work, since it (seems to be) incredibly expensive to measure rendered elements.
Try this. For any reasonable N, it should do the job:
function format(srcString, lines) {
var target = "";
var arr = srcString.split(" ");
var c = 0;
var MAX = Math.ceil(srcString.length / lines);
for (var i = 0, len = arr.length; i < len; i++) {
var cur = arr[i];
if(c + cur.length > MAX) {
target += '\n' + cur;
c = cur.length;
}
else {
if(target.length > 0)
target += " ";
target += cur;
c += cur.length;
}
}
return target;
}
alert(format("this is a very very very very " +
"long and convoluted way of creating " +
"a very very very long string",7));
You may want to give this solution a try, using canvas. It will need optimization and is only a quick shot, but I think canvas might be a good idea as you can calculate real widths. You can also adjust the font to the really used one, and so on. Important to note: This won't be the most performant way of doing things. It will create a lot of canvases.
DEMO
var t = `However, I don't care that much about optimization. As long as the lines are (in most cases) roughly even, I'm fine if the solution doesn't work in every single edge case, or can't be proven to be the least time complexity. I just need a real world solution that can take a string, and a number of lines (greater than 2), and give me back an array of strings that will usually look pretty even.`;
function getTextTotalWidth(text) {
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
ctx.font = "12px Arial";
ctx.fillText(text,0,12);
return ctx.measureText(text).width;
}
function getLineWidth(lines, totalWidth) {
return totalWidth / lines ;
}
function getAverageLetterSize(text) {
var t = text.replace(/\s/g, "").split("");
var sum = t.map(function(d) {
return getTextTotalWidth(d);
}).reduce(function(a, b) { return a + b; });
return sum / t.length;
}
function getLines(text, numberOfLines) {
var lineWidth = getLineWidth(numberOfLines, getTextTotalWidth(text));
var letterWidth = getAverageLetterSize(text);
var t = text.split("");
return createLines(t, letterWidth, lineWidth);
}
function createLines(t, letterWidth, lineWidth) {
var i = 0;
var res = t.map(function(d) {
if (i < lineWidth || d != " ") {
i+=letterWidth;
return d;
}
i = 0;
return "<br />";
})
return res.join("");
}
var div = document.createElement("div");
div.innerHTML = getLines(t, 7);
document.body.appendChild(div);
I'm sorry this is C#. I had created my project already when you updated your post with the Javascript tag.
Since you said all you care about is roughly the same line length... I came up with this. Sorry for the simplistic approach.
private void DoIt() {
List<string> listofwords = txtbx_Input.Text.Split(' ').ToList();
int totalcharcount = 0;
int neededLineCount = int.Parse(txtbx_LineCount.Text);
foreach (string word in listofwords)
{
totalcharcount = totalcharcount + word.Count(char.IsLetter);
}
int averagecharcountneededperline = totalcharcount / neededLineCount;
List<string> output = new List<string>();
int positionsneeded = 0;
while (output.Count < neededLineCount)
{
string tempstr = string.Empty;
while (positionsneeded < listofwords.Count)
{
tempstr += " " + listofwords[positionsneeded];
if ((positionsneeded != listofwords.Count - 1) && (tempstr.Count(char.IsLetter) + listofwords[positionsneeded + 1].Count(char.IsLetter) > averagecharcountneededperline))//if (this is not the last word) and (we are going to bust the average)
{
if (output.Count + 1 == neededLineCount)//if we are writting the last line
{
//who cares about exceeding.
}
else
{
//we're going to exceed the allowed average, gotta force this loop to stop
positionsneeded++;//dont forget!
break;
}
}
positionsneeded++;//increment the needed position by one
}
output.Add(tempstr);//store the string in our list of string to output
}
//display the line on the screen
foreach (string lineoftext in output)
{
txtbx_Output.AppendText(lineoftext + Environment.NewLine);
}
}
(Adapted from here, How to partition an array of integers in a way that minimizes the maximum of the sum of each partition?)
If we consider the word lengths as a list of numbers, we can binary search the partition.
Our max length ranges from 0 to sum (word-length list) + (num words - 1), meaning the spaces. mid = (range / 2). We check if mid can be achieved by partitioning into N sets in O(m) time: traverse the list, adding (word_length + 1) to the current part while the current sum is less than or equal to mid. When the sum passes mid, start a new part. If the result includes N or less parts, mid is achievable.
If mid can be achieved, try a lower range; otherwise, a higher range. The time complexity is O(m log num_chars). (You'll also have to consider how deleting a space per part, meaning where the line break would go, features into the calculation.)
JavaScript code (adapted from http://articles.leetcode.com/the-painters-partition-problem-part-ii):
function getK(arr,maxLength) {
var total = 0,
k = 1;
for (var i=0; i<arr.length; i++) {
total += arr[i] + 1;
if (total > maxLength) {
total = arr[i];
k++;
}
}
return k;
}
function partition(arr,n) {
var lo = Math.max(...arr),
hi = arr.reduce((a,b) => a + b);
while (lo < hi) {
var mid = lo + ((hi - lo) >> 1);
var k = getK(arr,mid);
if (k <= n){
hi = mid;
} else{
lo = mid + 1;
}
}
return lo;
}
var s = "this is a very very very very "
+ "long and convoluted way of creating "
+ "a very very very long string",
n = 7;
var words = s.split(/\s+/),
maxLength = partition(words.map(x => x.length),7);
console.log('max sentence length: ' + maxLength);
console.log(words.length + ' words');
console.log(n + ' lines')
console.log('')
var i = 0;
for (var j=0; j<n; j++){
var str = '';
while (true){
if (!words[i] || str.length + words[i].length > maxLength){
break
}
str += words[i++] + ' ';
}
console.log(str);
}
Using the Java String Split() Method to split a string we will discover How and Where to Apply This String Manipulation Technique:
We'll examine the Java Split() method's explanation and discover how to apply it. The principles are explained simply and with enough programming examples, either as a separate explanation or in the comment part of the programs.
The Java String Split() method is used to divide or split the calling Java String into pieces and return the Array, as the name implies. The delimiters("", " ", ) or regular expressions that we have supplied separately for each component or item of an array.
Syntax
String[ ] split(String regExp)
First Case: It involves initializing a Java String variable with a variety of words separated by spaces, using the Java String Split() method, and evaluating the results. We can effectively print each word without the space using the Java Split() function.
Second Case: In this case, we initialize a Java String variable and attempt to split or deconstruct the main String variable to use the String Split() method utilizing a substring of the initialized String variable.
Third Case: In this case, we will attempt to split a String using its character by taking a String variable (a single word).
You can check out other approaches to this problem on YouTube and even coding websites on google such as Coding Ninjas
This old question was revived by a recent answer, and I think I have a simpler technique than the answers so far:
const evenSplit = (text = '', lines = 1) => {
if (lines < 2) {return [text]}
const baseIndex = Math .round (text .length / lines)
const before = text .slice (0, baseIndex) .lastIndexOf (' ')
const after = text .slice (baseIndex) .indexOf (' ') + baseIndex
const index = after - baseIndex < baseIndex - before ? after : before
return [
text .slice (0, index),
... evenSplit (text .slice (index + (before > -1 ? 1 : 0)), lines - 1)
]
}
const text = `However, I don't care that much about optimization. As long as the lines are (in most cases) roughly even, I'm fine if the solution doesn't work in every single edge case, or can't be proven to be the least time complexity. I just need a real world solution that can take a string, and a number of lines (greater than 2), and give me back an array of strings that will usually look pretty even.`
const display = (lines) => console .log (lines .join ('\n'))
display (evenSplit (text, 7))
display (evenSplit (text, 5))
display (evenSplit (text, 12))
display (evenSplit (`this should be three lines, but it has a loooooooooooooooooooooooooooooooong word`, 3))
.as-console-wrapper {max-height: 100% !important; top: 0}
It works by finding the first line then recurring on the remaining text with one fewer lines. The recursion bottoms out when we have a single line. To calculate the first line, we take an initial target index which is just an equal share of the string based on its length and the number of lines. We then check to find the closest space to that index, and split the string there.
It does no optimization, and could certainly be occasionally misled by long words, but mostly it just seems to work.

How to detect char sequences where each successive char differs from the previous one by minimal alphabetical difference (1)?

I want to detect sequences of characters where each successive char differs from the previous one by 1, where 1 is its "alphabetical difference". In the standard alphabet, index("b")-index("a")=1, index("z")-index("y")=1, index("z")-index("x")=2, and so on.
What I want is to replace such sequences with its first and last chars, removing everything that is between. Note that if there are only two chars in such sequence, there is no need to replace. And there is no need to replace if the order is reverse, e.g. "dcba".
For example,
"dabcehklopqrsafxwvu012345678910210"
should be transformed into
"dacehklosafxwvu0910210"
Interesting, yesterday I solved exactly the same problem :).
Take a try with the following solution:
var str = "dabcehklopqrsafxwvu012345678910210";
var res = Array.prototype.reduce.call(str, function(acc, item, index, strAr) {
var pushItem =
//first item always included
index === 0 ||
// last item always included
index === strAr.length - 1 ||
// include the first item in sequence
strAr[index - 1].charCodeAt(0) + 1 !== item.charCodeAt(0) ||
// include the last item in sequence
strAr[index + 1].charCodeAt(0) - 1 !== item.charCodeAt(0)
if (pushItem) {
acc += item;
}
return acc;
}, '');
console.log(res); // prints "dacehklosafxwvu0910210"
Check the working demo.
A single loop solution
var code = 'dabcehklopqrsafxwvu012345678910210',
result = '',
i = 0, l;
for (i = 0, l = code.length; i < l; i++) {
result +=
i > 0 &&
i + 1 < l &&
code.charCodeAt(i - 1) + 1 === code.charCodeAt(i) &&
code.charCodeAt(i) + 1 === code.charCodeAt(i + 1) ?
'' :
code[i];
}
document.write(result);
I think the sample answer that you typed is not correct... as you still have kl after each other...
anyways, your code should looks like something like below:
var x = "dabcehklopqrsafxwvu012345678910210";
var z = x;
for (var i = 1; i < x.length - 1; i++)
if (x.charCodeAt(i) == x.charCodeAt(i + 1) - 1) {
x = x.replace(x.charAt(i) + x.charAt(i + 1), x.charAt(i));
}
alert(x);
The question here is if 12345 should it be 135, in your sample klopq became klo ...?

Looping over numbers

So this is the question that is given.
You are in a room with a circle of 100 chairs. The chairs are numbered sequentially from 1 to 100.
At some point in time, the person in chair #1 will be asked to leave. The person in chair #2 will be skipped, and the person in chair #3 will be asked to leave. This pattern of skipping one person and asking the next to leave will keep going around the circle until there is one person left, the survivor.
And this is the answer I came up with. I believe this is the right answer, I've done it on paper about 10 times as well and came up with 74 every time.
Is this a trick question or something? Because I'm not sure what to do from here.
Here is the jsfiddle http://jsfiddle.net/cQUaH/
var console = {
log : function(s) {
document.body.innerHTML += s + "<br>";
}
};
var chairArr = [];
for (var i = 1; i <= 100; i++){
chairArr.push(i);
}
var j = 2;
while(chairArr.length > 1) {
console.log('removing ' + chairArr[j]);
chairArr.splice(j, 1);
j++;
if(j >= chairArr.length) {
console.log('--- Finished pass');
console.log('--- Array state:');
console.log(chairArr);
j = (j == chairArr.length) ? 0 : 1;
}
}
console.log('--- Final result: ' + chairArr);
//result 74
With a minor change in indices, you have the Josephus problem. In the traditional formulation, person 1 kills person 2, 3 kills 4, etc. To convert to that form, kill off person 1, as your problem states, and then renumber people 2-100 by subtracting 1, giving people 1-99.
A good treatment of the Josephus problem, including an account of its origin in the Jewish Revolt of 70-73 CE, is in Concrete Mathematics, 2nd edition, by Graham, Knuth, and Patashnik, Section 1.3. Both Wikipedia and Wolfram MathWorld have articles on the problem, Wikipedia even includes the original description by Josephus in The Jewish War.
The book gives a mildly complicated recursion for the solution, and a simpler algorithm. If the number of people is n, and n = 2^l + m where l is as large as possible, then the answer is 2m+1. So, since 99 = 2^6 + 35, the solution is 2*35 + 1 = 71. But you need to reverse the renumbering, so the real answer is 72.
As far as your programming problem, however, why don't you take as your basic operation Remove the first person in the circle and move the second person to the end. So, with 5 people, [1,2,3,4,5], you remove the first getting [2,3,4,5]and moving the new first element to the end getting [3,4,5,2].
var killAndRotate = function(array) { // say [1,2,3,4,5]
var dead = array.shift(), // dead = 1, array = [2,3,4,5]
skipped = array.shift(); // skipped = 2, array = [3,4,5]
array.push(skipped); // array = [3,4,5,2]
}
And then the main loop becomes:
while (chairArray.length > 1) {
killAndRotate(chairArray);
}
alert(chairArray[0]); // or console.log, or return.
// In turn, array is:
// [1,2,3,4,5]
// [3,4,5,2]
// [5,2,4]
// [4,2]
// [2] and we alert, log, or return 2.
Added
The easy way to find that result for the original Josephus problem is to see that:
If there are 2^l people, then in the first pass all the even-numbered people are killed, so the first person remains alive.
1 2 3 4 5 6 7 8
X X X X
Now there are 2^(l - 1) people. Again, the first person survives:
1 2 3 4 5 6 7 8
X X X X
X X
Repeat the process; the first person survives each pass, and so is the last survivor.
Now, suppose there are m extra people with m < 2^l. Here, l = 3 and m = 5. Kill the first m people to die.
1 2 3 4 5 6 7 8 9 10 11 12 13
X X X X X Y
Now, there are 2^l people left, and person 2 m + 1 = 11 is the first in line. So he survives.
One should also point out that adding a new index variable and splicing can lead to programmer error. Since you only need to remove from the front and add to the back, use the basic methods of arrays.
It seems to me the answer is 72. When you realize that rather than removing numbers you can skip them, the code becomes very short and straight-forward.
var chairArr = [];
for (var i = 1; i <= 100; i++)
chairArr.push(i);
for (i = 1; i < chairArr.length-2; i = i + 2)
chairArr.push(chairArr[i]);
console.log('--- Final result: ' + chairArr[i]);
What have you described here is the Josephus problem, and can be solved using dynamic programming:
function josephus(n, k)
{
if (n == 1) {
return 1;
} else {
return ((josephus(n-1, k) + k - 1) % n) + 1;
}
}
alert(josephus(100, 2));
Source: Wikipedia
The n denotes the number of chairs and k indicates every kth person leaving.
The result here is 73.
Update
Unfortunately, I didn't read the problem properly. The above code solves a slightly different problem; instead of killing off the first person in round one, the second person is killed instead. Being a survivor hinges on details :)
Solving your code problem is rather simple, start with the first person instead of the third in the first round.
var chairArr = [];
for (var i = 1; i <= 100; i++){
chairArr.push(i);
}
var j = 0;
while (chairArr.length > 1) {
chairArr.splice(j, 1);
j = (j + 1) % n;
}
You don't need an iteration to find the result, there is a formula that can be use to obtain the final chair:
function findChair (input) {
return (input - Math.pow(2, Math.floor(Math.log2(input)))) * 2 || (input === 1 ? 0 : input)
}
And for the original Josephus problem, which you kill the even numbers instead, the formula can be simplified:
function findChair (input) {
return (input - Math.pow(2, Math.floor(Math.log2(input)))) * 2 + 1
}
The cool thing about the original problem, is that you can work with binary. For example:
100 = 1100100
Take the first '1' and place it to the last:
1001001 = 73

Categories