Javascript-форум (https://javascript.ru/forum/)
-   Оффтопик (https://javascript.ru/forum/offtopic/)
-   -   Задачка на сообразительность (https://javascript.ru/forum/offtopic/15269-zadachka-na-soobrazitelnost.html)

with-love-from-siberia 20.02.2011 14:36

Matre,
Дело не в браузерах, дело в алгоритме. Он работает неверно. Проверьте на любых примерах. Например:
String.prototype.index = function (str) {
	var j = -1, c = false, L1 = this.length, L2 = str.length - 1;
	for (var i = 0; i < L1; i++) {
		if (str.charAt(0) === this.charAt(i))
			c = true, j = i;
		if (c && i === j + L2)
			return j;
		if (c && str.charAt(i) != this.charAt(i + j))
			c = false;
	}
	return j;
};

// Где ищем
var s = 'A';
// Что ищем
var t = 'AB';

alert([
	'В строке "' + s + '"', 
	'ищем "' + t + '"', 
	'и находим: ' + s.index(t), // Должно быть -1, показывает 0
	'хотя там быть не должно: ' + s.indexOf(t) // Показывает -1
].join('\n'));

B@rmaley.e><e 20.02.2011 14:56

рони,
String.prototype.index = function (c) {
    for (var a = -1, d = this.length, b = 0; b < d; b++) {
        if(c.length > d) return a;
        a++;
        a = c.charAt(a) === this.charAt(b) ? a : c.charAt(0) === this.charAt(b) ? 0 : -1;
        if (a == c.length - 1) return b - c.length + 1
    }
    return a
};
var s1 = 'aababaO_o',
     l1 = 'abaO', l2 = 'abac', l3 = 'aa', l4 = 'O_o';
alert( [
 [s1.index(l1), s1.indexOf(l1)]
].join('\n') )


Matre, вполне нормальный. Причем точно такие же результаты будут у других пользователей.
А вот алгоритм у Вас кривой.

Принимая во внимание то, что все известные алгоритмы поиска подстроки требуют либо предварительной обработки данных, либо работают дольше, чем за O(n), маловероятно, что существует алгоритм, позволяющий "с места", без подготовки найти заданную подстроку в строке за один просмотр исходной строки.

Gvozd 20.02.2011 15:19

Цитата:

Сообщение от B@rmaley.e><e
Принимая во внимание то, что все известные алгоритмы поиска подстроки требуют либо предварительной обработки данных, либо работают дольше, чем за O(n), маловероятно, что существует алгоритм, позволяющий "с места", без подготовки найти заданную подстроку в строке за один просмотр исходной строки.

http://algolist.manual.ru/search/esearch/kmp.php
Работает за линию от входных данных.
Но условие задачи было не обеспечить определенную сложность алгоритма, а использовать только один цикл.
Сделать из группы вложенных циклов, или из группы подряд идущих циклов, один единственный - вполне решаемая задача, хотя и из разряда "никогда так не делай"

Sweet 20.02.2011 15:48

Я бы реализовал вот так:
String.prototype.index = function(x){
  var i1, i2, l1 = this.length, l2 = x.length;

  for(i1 = 0; i1 < l1; i1++)
    if(this[i1] === x[0])
      for(i2 = 0; i2 <= l2; i2++){
        if(i2 === l2) return i1;
        if(this[i1 + i2] === x[i2]) continue;
        break;
      };
  return -1;
};

var s1 = 'aababaO_o', 
    l1 = 'abaO', l2 = 'abac', l3 = 'aa', l4 = 'O_o'; 
alert( [ 
  [s1.index(l1), s1.indexOf(l1)],
  [s1.index(l2), s1.indexOf(l2)],
  [s1.index(l3), s1.indexOf(l3)],
  [s1.index(l4), s1.indexOf(l4)] 
].join('\n') );

рони 20.02.2011 16:11

Ещё вариант ...
String.prototype.index = function (c) {
    for (var a = -1, d = this.length, b = 0; b < d; b++) {
        if (c.length > d) break;
        a++;
        if (c.charAt(a) !== this.charAt(b)) {
            b -= a;
            a = -1
        }
        if (a == c.length - 1) return b - c.length + 1
    }
    return a
};
var s1 = 'aababaO_o',
     l1 = 'abaO', l2 = 'abac', l3 = 'aa', l4 = 'O_o';
alert( [
 [s1.index(l1), s1.indexOf(l1)]
].join('\n') )

// Где ищем
var s = 'A';
// Что ищем
var t = 'AB';

alert([
	'В строке "' + s + '"',
	'ищем "' + t + '"',
	'и находим: ' + s.index(t), // Должно быть -1, показывает 0
	'хотя там быть не должно: ' + s.indexOf(t) // Показывает -1
].join('\n'));

var s1 = 'aababaO_o',
     l1 = 'aba', l2 = 'abac', l3 = 'aa', l4 = 'O_o';

alert( [
 [s1.index(l1), s1.indexOf(l1)],
 [s1.index(l2), s1.indexOf(l2)],
 [s1.index(l3), s1.indexOf(l3)],
 [s1.index(l4), s1.indexOf(l4)]
].join('\n') )

Vulkan 20.02.2011 16:18

Sweet, можно только один цикл использовать.

Sweet 20.02.2011 16:25

Цитата:

Сообщение от Vulkan
можно только один цикл использовать.

А мне захотелось использовать два!:) Хотя, конечно, можно еще было бы вместо for воспользоваться while, или вообще без циклов...

B@rmaley.e><e 20.02.2011 16:27

Цитата:

Сообщение от Gvozd
Сделать из группы вложенных циклов, или из группы подряд идущих циклов, один единственный - вполне решаемая задача

Как Вы собрались объединять, например, это?
var arr = [3,4,5,6,7,8,9,0,1 /* and so on */], s = 0;
for(var i =0, length = arr.length; i < length; ++i){ // предварительные вычисления
  s += arr[i];
}

for(var i = 0, length = arr.length; i < length; ++i){ // самое то.
  arr[i] = (arr[i] / s * 100).toFixed(2) + '%';
}
alert([s, arr].join('\n'));

Сомневаюсь, что КМП можно записать одним циклом.

P.S. Грязные "хаки" вида
function indexOf(haystack, needle){
  var n = haystack.length,
       m = needle.length;
  var i = 0, j = 0, offset = 0;
  for(var k = 0, length = n * m; k < length; ++k){
    i = k / m | 0;
    j = k % m;
    if(haystack[i + offset] != needle[j]){
      offset = 0;
      k += m - j - 1;
    } else {
      ++offset;
      if(j == m - 1) return i;
    }
  }
  return -1;
}

var s1 = 'aababaO_o',  
    l1 = 'abaO', l2 = 'abac', l3 = 'aa', l4 = 'O_o';  
alert( [  
  [indexOf(s1, l1), s1.indexOf(l1)],
  [indexOf(s1, l2), s1.indexOf(l2)],
  [indexOf(s1, l3), s1.indexOf(l3)],
  [indexOf(s1, l4), s1.indexOf(l4)],
  [indexOf(s1, 'a'), s1.indexOf('a')]
].join('\n') );
не рассматриваем.

with-love-from-siberia 20.02.2011 17:02

Эта задача не требует хаков, или дополнительных циклов. Задача действительно решается в один цикл. Не надо городить огород:
String.prototype.hasAt = function(needle, pos)
{
	var i = Math.min(this.length, Math.max(0, Number(pos) || 0));
	var j;
	var found;
	for ( ; i < this.length; i++) {
		if ( found ) {
			if ( i - j == needle.length ) {
				return j;
			}
			found = this.charAt(i) == needle.charAt(i - j);
		} else {
			found = this.charAt(i) == needle.charAt(0);
			if ( found ) {
				j = i;
			}
		}
	}
	return found && this.length - j == needle.length 
		? j 
		: -1;
};

Для "чистоты" эксперимента следовало бы заменить Math.min/Math.max соответствующими проверочными условиями, чтобы позиция начала поиска не выходила за пределы строки. Но это не существенно.

B@rmaley.e><e 20.02.2011 17:34

String.prototype.hasAt = function(needle, pos)
{
	var i = Math.min(this.length, Math.max(0, Number(pos) || 0));
	var j;
	var found;
	for ( ; i < this.length; i++) {
		if ( found ) {
			if ( i - j == needle.length ) {
				return j;
			}
			found = this.charAt(i) == needle.charAt(i - j);
		} else {
			found = this.charAt(i) == needle.charAt(0);
			if ( found ) {
				j = i;
			}
		}
	}
	return found && this.length - j == needle.length 
		? j 
		: -1;
};

var s1 = 'aababababaO_o',   
    l1 = 'ababaO';   
alert( [
  [s1.hasAt(l1), s1.indexOf(l1)] 
].join('\n') );


Кто еще верит, что все так просто?


Часовой пояс GMT +3, время: 09:58.