算法题--华为od机试考试(根据某条件聚类最小交换次数、计算面积、连续出牌数量)

目录

根据某条件聚类最小交换次数

题目描述

数据范围

输入描述

输出描述

备注

示例1

输入

输出

解析

答案

计算面积

题目描述

输入描述

取值范围

输出描述

示例一

输入

输出

解析

答案

连续出牌数量

题目描述

输入描述

输出描述

示例1

输入

输出

解析

答案


根据某条件聚类最小交换次数

考察滑动窗口

题目描述

给出数字K,请输出所有结果小于K的整数组合到一起的最小交换次数。组合一起是指满足条件的数字相邻,不要求相邻后在数组中的位置。

数据范围

-100<=K<=100

-100<=数组中的数值<=100

输入描述

第一行输入数组:1 3 1 4 0

第二行输入K数值:2

输出描述

第一行输出最小较好次数:1

备注

小于2的表达式是1 1 0,共三种可能将所有符合要求数字组合一起,最小交换1次

示例1

输入

1 3 1 4 0

2

输出

1

解析

先找到满足小于K的数量,得到滑动窗口的大小,从左到右滑动窗口,记录窗口中>=K的整数数量即为需要交换的次数,当窗口中>=K的数量最小的时候为最小的交换次数。

答案

function minSwap(str, k) {
    let arr = str.split(' ')
    let len = arr.filter(v => v < k).length
    if (arr.length === len) {
        return 0
    }
    if (len === 0) {
        return false
    }
    let min = arr.slice(0, len).filter(v => v >= k).length
    let num = min
    let i = len
    while (i <= arr.length) {
        i++
        // 出去的数大于等于k,窗口中不满足条件的数减一
        if (arr[i - len - 1] >= k) {
            num--
        }
        // 进来的数大于k,窗口中不满足条件的数加一
        if (arr[i] >= k) {
            {
                num++
            }
            // 判断窗口中的不满足条件的数是否为最小的
            if (num < min) {
                min = num
            }
        }
    }
    return min
}
console.log(minSwap('1 3 1 4 0', 2))

计算面积

画图、hash和理解能力。

题目描述

绘图机器的绘图笔初始位置在圆点(0,0),机器启动后其绘图笔按下面规则绘制直线:

1)尝试沿着横向坐标轴正向绘制直线,直到给定的终点值E。

2)期间可通过指令在纵坐标轴方向进行偏移,并同时绘制直线,偏移后按规则1绘制直线;指令的格式为X offsetY,表示在横坐标X沿纵坐标方向偏移,offsetY为正数表示正向偏移,为负数表示负向偏移。

给定了横坐标终点值E、以及若干条绘制指令,请计算绘制的直线和横坐标轴、以及X=E的直线组成图形

的面积

输入描述

首行为两个整数N E,表示有N条指令,机器运行的横坐标终点值E。

接下来N行,每行两个整数表示一条绘制指令X offsetY,用例保证横坐标X以递增排序方式出现,且不会出现相同横坐标X。

取值范围

0<N<=10000,0<=X<=E<=20000,-10000<=offsetY<=10000.

输出描述

一个整数,表示计算得到的面积,用例保证,结果范围在0~4294967295内.

示例一

输入

4 10

1 1

2 1

3 1

4 -2

输出

12

解析

通过画图得到目标区域的面积,从0~E分为E个长方形,每向右走一格,算一个的高度和当前的面积。

答案

function getArea(str) {
    let arr = str.split('\n')
    let first = arr.shift().split(' ')
    let E = first[1]
    let instruct = {}
    arr = arr.forEach(v => {
        let tmp = v.split(' ')
        instruct[tmp[0]] = tmp[1]
    })
    let area = 0
    let y = 0
    for (let i = 0; i < E; i++) {
        // 每向右走一格,算一个的高度和当前的面积。
        if (instruct[i]) {
            y += Number(instruct[i])
        }
        if (y) {
            area += Math.abs(y)
        }
    }
    return area
}

console.log(getArea(`4 10
1 1
2 1
3 1
4 -2`))

连续出牌数量

深度遍历算法、递归。

题目描述

有这么一款单人卡牌游戏,牌面由颜色和数字组成,颜色为红、黄、蓝、绿中的一种,数字为0~9中的一个。游戏开始时玩家从手牌中选取一张卡牌打出,接下来如果玩家手中有和他上一次打出的手牌颜色或者数字相同的手牌,他可以继续将该手牌打出,直至手牌打光或者没有符合条件可以继续打出的手牌。

现给定一副手牌,请找到最优的出牌策略,使打出的手牌最多。

输入描述

输入为两行,第一行是每张手牌的数字,数字由空格分隔,第二张为对应的每张手牌的颜色,用r y b g这4个字母分别代表4种颜色,字母也由空格分隔。手牌数量不超过10.

输出描述

输出一个数字,即最多能打出的手牌的数量。。

示例1

输入

1 4 3 4 5

r y b b r

输出

3

解析

通过数组记录所有的手牌,每个手牌为一个对象,对象上属性有牌号、颜色、是否使用过。通过for循环一次出每一张牌,通过findMax函数返回出当前牌的最大出牌数。比较取最大值。

关键在于findMax函数函数实现:

1.确定入参,1>当前所有牌的状态、2>上一次出的牌、3>当前的次数。1、2用于查找能出的牌以及是否出牌结束,3记录结果。

2.确定f(x)和f(x-1)的关系。f(x)=Max(f(x-1)...)。当前这一次等于下一次中取最大的次数。通过for循环比较每一次出牌的最大值,并且需要注意递归回来后需要将牌的状态设置为未出状态

3.出口,当没有下一张可出的牌时返回当前记录的记过。

答案

function maxCard(str) {
    let data = str.split('\n')
    let card = []
    data[0].split(' ').forEach(v => {
        card.push({ value: v, isUse: 0 })
    })
    data[1].split(' ').forEach((v, i) => {
        card[i].color = v
    })
    max = 0
    for (let i = 0; i < card.length; i++) {
        // 设置出了该牌
        card[i].isUse = 1
        res = findMax(card, card[i], 1)
        if (max < res) {
            max = res
        }
        // 还原该牌的状态
        card[i].isUse = 0
    }
    return max
}
function findMax(card, lastcard, num, max = 0) {
    let can = card.filter(v => !v.isUse && (v.color === lastcard.color || v.value === lastcard.value))
    let len = can.length
    // 出口:当没有下一张可出的牌
    if (len === 0) {
        return num
    }
    // 等于下一次中取最大的次数。
    for (let i = 0; i < len; i++) {
        // 设置出了该牌
        can[i].isUse = 1
        res = findMax(card, can[i], num + 1, max)
        if (max < res) {
            max = res
        }
        // 还原该牌的状态
        can[i].isUse = 0
    }
    return max
}
console.log(maxCard(`1 4 3 4 5
r y b b r`))

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值