Level
프로그래머스 Lv3
Recruitment
카카오 인턴십
// 보석 쇼핑 시간초과

function solution(gems) {
  const set = new Set();
  gems.forEach((gem) => set.add(gem));
  const gemSetSize = set.size;
  const gemsLength = gems.length;

  let comparator = {};
  const add = (gem) => {
    if (comparator[gem]) {
      comparator[gem]++;
      return;
    }
    comparator[gem] = 1;
    comparator.size++;
  };
  const substract = (gem) => {
    comparator[gem]--;
    comparator[gem] === 0 && comparator.size--;
  };

  let length = gemSetSize;

  while (length <= gemsLength) {
    comparator = { size: 0 };
    let first = 0;
    let last = length - 1;

    for (let i = 0; i < length; i++) {
      const gem = gems[i];
      add(gem);
    }
    if (comparator.size === gemSetSize) {
      return [first + 1, last + 1];
    }
    // 012
    while (true) {
      last++;
      if (last === gemsLength) {
        break;
      }
      // 123, 234, 345
      substract(gems[first]);
      add(gems[last]);
      first++;
      if (comparator.size === gemSetSize) {
        return [first + 1, last + 1];
      }
    }
    length++;
  }
}
// set 사용 시간 초과
function solution(gems) {
  const set = new Set();
  gems.forEach((gem) => set.add(gem));
  const gemSetSize = set.size;
  const gemsLength = gems.length;

  const add = (comparator, gem) => {
    const gemCount = comparator.get(gem);
    gemCount ? comparator.set(gem, gemCount + 1) : comparator.set(gem, 1);
  };
  const substract = (comparator, gem) => {
    const gemCount = comparator.get(gem);
    gemCount > 1 ? comparator.set(gem, gemCount - 1) : comparator.delete(gem);
  };

  let length = gemSetSize;

  while (length <= gemsLength) {
    let comparator = new Map();
    for (let i = 0; i < length; i++) {
      const gem = gems[i];
      add(comparator, gem);
    }

    if (comparator.size === gemSetSize) {
      return [1, length];
    }

    let first = 0;
    let last = length - 1;
    // 012
    while (true) {
      last++;
      if (last === gemsLength) {
        break;
      }
      // 123, 234, 345
      substract(comparator, gems[first]);
      add(comparator, gems[last]);
      first++;
      if (comparator.size === gemSetSize) {
        return [first + 1, last + 1];
      }
    }
    length++;
  }
}

for (let i = 0; i < last - 1; i++) {
  add(comparator, gems[last]);
}
while (true) {
  if (start === 0) {
    add(comparator, gems[last]);
    if (comparator.size === gemSetSize) {
      return [first + 1, last + 1];
    }
    while (true) {
      last++;
      if (last === gemsLength) {
        break;
      }
      substract(comparator, first);
      first++;
      add(comparator, last);
      if (comparator.size === gemSetSize) {
        return [first + 1, last + 1];
      }
    }
  }
  if (end === gemsLength) {
    first--;
    add(comparator, gems[first]);
    if (comparator.size === gemSetSize) {
      return [first + 1, last + 1];
    }
    while (true) {
      first--;
      last--;
      if (first === -1) {
        break;
      }
      add(comparator, gems[first]);
      substract(comparator, gems[last]);
      if (comparator.size === gemSetSize) {
        return [first + 1, last + 1];
      }
    }
  }
}
// sliding left to right, right to left 여전히 시곤초과
function solution(gems) {
  const set = new Set();
  gems.forEach((gem) => set.add(gem));
  const gemSetSize = set.size;
  const gemsLength = gems.length;

  const add = (comparator, gem) => {
    const gemCount = comparator.get(gem);
    gemCount ? comparator.set(gem, gemCount + 1) : comparator.set(gem, 1);
  };
  const substract = (comparator, gem) => {
    const gemCount = comparator.get(gem);
    gemCount > 1 ? comparator.set(gem, gemCount - 1) : comparator.delete(gem);
  };

  let comparator = new Map();
  let first = 0;
  let last = gemSetSize - 1;

  for (let i = 0; i < last; i++) {
    add(comparator, gems[i]);
  }

  // 01
  while (true) {
    console.log(first, last);
    if (first === 0) {
      add(comparator, gems[last]);
      // 012
      if (comparator.size === gemSetSize) {
        return [first + 1, last + 1];
      }
      while (true) {
        if (last + 1 === gemsLength) {
          break;
        }
        substract(comparator, gems[first]);
        first++;
        last++;
        add(comparator, gems[last]);
        // 123, first:1, last:3
        // 234
        // 345
        if (comparator.size === gemSetSize) {
          return [first + 1, last + 1];
        }
      }
      continue;
    }

    if (last === gemsLength - 1) {
      first--;
      add(comparator, gems[first]);
      if (comparator.size === gemSetSize) {
        return [first + 1, last + 1];
      }
      while (true) {
        if (first - 1 === -1) {
          break;
        }
        substract(comparator, gems[last]);
        last--;
        first--;
        add(comparator, gems[first]);
        if (comparator.size === gemSetSize) {
          return [first + 1, last + 1];
        }
      }
      last++;
    }
  }
}

// 투포인터 사용 통과

function solution(gems) {
  const set = new Set(gems);
  const gemSetSize = set.size;
  const gemsLength = gems.length;

  const add = (comparator, gem) => {
    const gemCount = comparator.get(gem);
    gemCount ? comparator.set(gem, gemCount + 1) : comparator.set(gem, 1);
  };
  const substract = (comparator, gem) => {
    const gemCount = comparator.get(gem);
    gemCount > 1 ? comparator.set(gem, gemCount - 1) : comparator.delete(gem);
  };

  let start = 0;
  let end = 0;
  let comparator = new Map();
  const stack = [];

  while (true) {
    if (end === gemsLength) {
      break;
    }

    add(comparator, gems[end]);

    if (comparator.size === gemSetSize) {
      while (comparator.size === gemSetSize) {
        substract(comparator, gems[start]);
        start++; // start 포인터 이동
      }
      stack.push([start - 1, end]);
    }

    end++; // end 포인터 이동
  }

  // 최소값 찾기
  let min = Infinity;
  let minIndex = 0;
  stack.forEach((item, i) => {
    const [front, end] = item;
    if (end - front < min) {
      min = end - front;
      minIndex = i;
    }
  });
  return stack[minIndex].map((i) => i + 1);
}