sisterAn / JavaScript-Algorithms

基础理论+JS框架应用+实践,从0到1构建整个前端算法体系

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

字节算法题:扑克牌问题

sisterAn opened this issue · comments

魔术师手中有一堆扑克牌,观众不知道它的顺序,接下来魔术师:

  • 从牌顶拿出一张牌, 放到桌子上
  • 再从牌顶拿一张牌, 放在手上牌的底部

如此往复(不断重复以上两步),直到魔术师手上的牌全部都放到了桌子上。

此时,桌子上的牌顺序为: (牌顶) 1,2,3,4,5,6,7,8,9,10,11,12,13 (牌底)。

问:原来魔术师手上牌的顺序,用函数实现。

感谢 @Eileenxj 的指出,已调整

解答:反向推导

假设,原来魔术师手上牌的顺序数组为 origin ,最后放在桌子上的顺序数组为 result

正向的操作为: origin 取出第一个插入 result 前面, origin 再取出第一个换到自己的末尾,如此重复;

反向操作为: origin 最后一个放到自己的第一个前面, result 拿出第一个插入 origin 前面,如此重复;

const calc = (arr) => {
    const origin = [];
    for (let i = 0; i < arr.length; i++) {
        if (origin.length) {
            const item = origin.pop();
            origin.unshift(item);
        }
        origin.unshift(result[i])
    }
    return origin;
}

// 测试
const result = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
// 原有顺序
calc(result)
// [13, 2, 12, 6, 11, 3, 10, 5, 9, 1, 8, 4, 7]

最近刚好在面试里遇到了这道题,说下当时的思路:这是一个已知结果倒推的过程,可以把过程想象为动作的倒放,即:纸牌从桌上返回到手里的过程
原始的扑克牌顺序存放:牌顶 => 牌底 ,用一个数组存放,base=[]
既成现实的桌面纸牌顺序:牌顶 => 牌底,res = [13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
正常操作顺序为: base 拿出第一个插入 res 前面, base 再拿出第一个换到自己的末尾, 如此重复
反向的顺序则为:base 最后一个放到自己的第一个前面, res 拿出第一个插入 base 前面, 如此重复

上代码

const res = [13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1] ;
const runBackward = () => {
    const base = [];
    for (let i = 0; i < res.length; i++) {
        if (base.length) {
            const item = base.splice(base.length - 1, 1)[0];
            base.unshift(item);
        }
        base.unshift(res[i])
    }
    return base;
}

最近刚好在面试里遇到了这道题,说下当时的思路:这是一个已知结果倒推的过程,可以把过程想象为动作的倒放,即:纸牌从桌上返回到手里的过程
原始的扑克牌顺序存放:牌顶 => 牌底 ,用一个数组存放,base=[]
既成现实的桌面纸牌顺序:牌顶 => 牌底,res = [13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
正常操作顺序为: base 拿出第一个插入 res 前面, base 再拿出第一个换到自己的末尾, 如此重复
反向的顺序则为:base 最后一个放到自己的第一个前面, res 拿出第一个插入 base 前面, 如此重复

上代码

const res = [13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1] ;
const runBackward = () => {
    const base = [];
    for (let i = 0; i < res.length; i++) {
        if (base.length) {
            const item = base.splice(base.length - 1, 1)[0];
            base.unshift(item);
        }
        base.unshift(res[i])
    }
    return base;
}

“将牌堆第一张放到桌子上,再将接下来的牌堆的第一张放到牌底”,照字面理解的话,我感觉两个数组的第一个数字应该是一样的?因为是先放第一张过去到桌子上,再去换牌堆的顺序?

最近刚好在面试里遇到了这道题,说下当时的思路:这是一个已知结果倒推的过程,可以把过程想象为动作的倒放,即:纸牌从桌上返回到手里的过程
原始的扑克牌顺序存放:牌顶 => 牌底 ,用一个数组存放,base=[]
既成现实的桌面纸牌顺序:牌顶 => 牌底,res = [13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
正常操作顺序为: base 拿出第一个插入 res 前面, base 再拿出第一个换到自己的末尾, 如此重复
反向的顺序则为:base 最后一个放到自己的第一个前面, res 拿出第一个插入 base 前面, 如此重复
上代码

const res = [13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1] ;
const runBackward = () => {
    const base = [];
    for (let i = 0; i < res.length; i++) {
        if (base.length) {
            const item = base.splice(base.length - 1, 1)[0];
            base.unshift(item);
        }
        base.unshift(res[i])
    }
    return base;
}

“将牌堆第一张放到桌子上,再将接下来的牌堆的第一张放到牌底”,照字面理解的话,我感觉两个数组的第一个数字应该是一样的?因为是先放第一张过去到桌子上,再去换牌堆的顺序?

你可以这么理解,有两个数组,一个是空数组A(桌子),另一个是B数组(牌堆),然后每次从B取出一张牌放到A数组,然后把B数组中的第一位取出来,放到B数组的最后一位

解答:反向推导

假设,原来魔术师手上牌的顺序数组为 origin ,最后放在桌子上的顺序数组为 result

正向的操作为: origin 取出第一个插入 result 前面, origin 再取出第一个换到自己的末尾,如此重复;

反向操作为: origin 最后一个放到自己的第一个前面, result 拿出第一个插入 origin 前面,如此重复;

const calc = (arr) => {
    const origin = [];
    for (let i = 0; i < arr.length; i++) {
        if (origin.length) {
            const item = origin.pop();
            origin.unshift(item);
        }
        origin.unshift(result[i])
    }
    return origin;
}

// 测试
const result = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
// 原有顺序
calc(result)
// [13, 2, 12, 6, 11, 3, 10, 5, 9, 1, 8, 4, 7]

你这个不对吧,导不出来呢

 const result = [1,2,3,4,5,6,7,8,9,10,11,12,13]
 const getOrigin = (arr)=>{
    let origin = []
    for(let i = arr.length-1; i>=0; i--) {
      if(origin.length) {
        let item = origin.shift()
        origin.push(item)
      }
      origin.push(arr[i])
    }
    return origin;
 }
 let res = getOrigin(result);
 console.log(res)
 // [ 1, 12, 2, 8, 3, 11, 4, 9, 5, 13, 6, 10, 7 ]
function undo(nums) {
  const result = [...nums];
  const origin = [];
  while (result.length) {
    origin.push(result.pop());
    if (result.length > 0)
      origin.push(origin.shift());
  }

  return origin;
}

function wash(nums) {
  const origin = [...nums];
  const result = [];

  while (origin.length) {
    result.push(origin.pop());
    if (origin.length > 0)
      origin.unshift(origin.pop())
  }
  return result;
}

const origin = undo([1,2,3,4,5,6,7,8,9,10,11,12,13])
console.log(origin); // 底 [7, 10, 6, 13, 5,  9, 4, 11, 3,  8, 2, 12, 1] 顶
console.log(wash(origin)) // 底 [1, 2, 3 ,4, 5, 6, 7, 8, 9, 10, 11, 12, 13] 顶

解答:反向推导

假设,原来魔术师手上牌的顺序数组为 origin ,最后放在桌子上的顺序数组为 result

正向的操作为: origin 取出第一个插入 result 前面, origin 再取出第一个换到自己的末尾,如此重复;

反向操作为: origin 最后一个放到自己的第一个前面, result 拿出第一个插入 origin 前面,如此重复;

const calc = (arr) => {
    const origin = [];
    for (let i = 0; i < arr.length; i++) {
        if (origin.length) {
            const item = origin.pop();
            origin.unshift(item);
        }
        origin.unshift(result[i])
    }
    return origin;
}

// 测试
const result = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
// 原有顺序
calc(result)
// [13, 2, 12, 6, 11, 3, 10, 5, 9, 1, 8, 4, 7]

你这个答案是针对 牌顶-》排底的result顺序吧,但是你题目又是说的 排底-》牌顶为 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]

commented
function getOrigin(result) {
// 设置原数组
    let origin = []
    while(result.length > 1) {
//取出结果中的最后一项,放入原数组中的最后一项,然后取出原数组第一项放入最后一项。
      let item = result.pop()
      origin.push(item)
      origin.push(origin.shift())
    }
// 最后一次放入的时候,不用调换位置
    origin.push(result.pop())
    return origin
  }
  console.log(getOrigin([1,2,3,4,5,6,7,8,9,10,11,12,13])) //[  7, 10, 6, 13, 5,  9,  4, 11, 3,  8, 2, 12, 1]

我这边写了个输入为牌底 -> 牌顶的~

const arrRes = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13];

const mySolution = (arrFinal) => {
    const arrOri = [];
    for(let i=1; i<=arrFinal.length; i++) {
      if(i===1 || i===arrFinal.length) {
        arrOri.unshift(arrFinal.slice(-i)[0]);
      } else {
        arrOri.unshift(arrFinal.slice(-i)[0]);
        const tmp = arrOri.splice(-1, 1)[0];
        arrOri.unshift(tmp);
      }
    }
    return arrOri;
}

console.log(mySolution(arrRes));

function cal(arr){
let old = []
for(let i=arr.length-1;i>=0;i--){
if(old.length){
let num = old.pop()
old.unshift(num)
}
old.unshift(arr[i])
}
return old
}
const result = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
console.log(cal(result)) // [1, 12, 2, 8, 3, 11, 4, 9, 5, 13, 6, 10, 7]

commented

`/**

  • 扑克牌问题
  • 反向推导
  • 手上有一副牌 arr[]
  • 1, 牌顶部拿出一张 arr.shift(), 放到桌子上 table.push
  • 2, 牌顶部拿出一张 arr.shift(), 放到牌底部 arr.push
  • 重复上面两步,得出 table = [1,2,3,4,5,6,7,8,9,10,11]
  • 求arr
  • 思考:反向推导:
    1. arr.pop() => arr.unshift()
    1. table.pop() => arr.unshift()
      */
      function reverseP(table) {
      let arr = []
      while(table.length) {
      let a = arr.pop()
      a && arr.unshift(a)
      let val = table.pop()
      arr.unshift(val)
      }
      console.log(arr, 'ad')
      return arr
      }
      reverseP([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13])
      // [
      1, 12, 2, 8, 3, 11,
      4, 9, 5, 13, 6, 10,
      7
      ]
      `
function getOrigin(arr = []) {
  let result = [];
  while (arr.length) {
    if (result.length > 1) result.unshift(result.pop());
    result.unshift(arr.shift());
  }
  return result;
}