牛客春招刷题训练营-2025.4.7题解

活动地址: 牛客春招刷题训练营 - 编程打卡活动

简单题 查找输入整数二进制中1的个数

方案一:使用 bits.OnesCount 函数

package main

import (
	"fmt"
	"math/bits"
)

func main() {
	var n, m uint
	fmt.Scan(&n, &m)
	fmt.Println(bits.OnesCount(n))
	fmt.Println(bits.OnesCount(m))
}

方案二:手动实现 countBits 函数

其中 n &= n - 1 用来清除最右边的 1

package main

import (
	"fmt"
)

func countBits(n uint) int {
	count := 0
	for n > 0 {
		n &= n - 1
		count++
	}
	return count
}

func main() {
	var n, m uint
	fmt.Scan(&n, &m)
	fmt.Println(countBits(n))
	fmt.Println(countBits(m))
}

中等题 宝石手串

  • 将原字符串 s 复制一份并拼接(s += s),这样可以处理环形的情况
  • 用哈希表 mp 记录每个字符最后一次出现的位置
  • 对于每个字符,查看它上一次出现的位置,计算中间需要移动的最小距离
  • 最终答案就是所有相同字符对之间最小的移动距离
package main

import "fmt"

func min(a, b int) int {
	if a < b {
		return a
	}
	return b
}

func solve(t int) {
	var (
		n int
		s string
	)
	fmt.Scan(&n, &s)
	s += s
	mp := make(map[rune]int)
	ans := n - 1
	for i, c := range s {
		if _, ok := mp[c]; ok {
			ans = min(ans, i-mp[c]-1)
		}
		mp[c] = i
	}
	if ans == n-1 {
		ans = -1
	}
	fmt.Println(ans)
}

func main() {
	var t int
	fmt.Scan(&t)
	for i := 0; i < t; i++ {
		solve(i)
	}
}

困难题 最长上升子序列(一)

方案一:线性DP 时间复杂度:

dp[i] 表示以第 i 个数结尾的最长递增子序列长度

  • 对于每个位置 i,初始化 dp[i] = 1(最短的递增子序列就是数字本身)
  • 遍历 i 前面的所有位置 j
  • 如果 a[i] > a[j],说明可以将第 i 个数接在以 j 结尾的递增子序列后面
  • 此时可以更新 dp[i] = max(dp[i], dp[j] + 1)
package main

import "fmt"

func max(a, b int) int {
	if a > b {
		return a
	}
	return b
}

func main() {
	var n int
	fmt.Scanf("%d", &n)
	a := make([]int, n)
	for i := range a {
		fmt.Scanf("%d", &a[i])
	}
	dp := make([]int, n)
	dp[0] = 1
	for i := 1; i < n; i++ {
		dp[i] = 1
		for j := 0; j < i; j++ {
			if a[i] > a[j] {
				dp[i] = max(dp[i], dp[j]+1)
			}
		}
	}
	ans := 0
	for _, v := range dp {
		ans = max(ans, v)
	}
	fmt.Println(ans)
}

方案二:贪心 + 二分查找 时间复杂度:

我们可以维护一个子序列 dp,其中 dp[i] 表示长度为 i+1 的上升子序列的最小结尾值,保证 dp 子序列一定是递增的

遍历所有的元素,如果当前元素比子序列中的最后一个元素还大,就将其添加到子序列的末尾

否则,我们可以用二分查找找到子序列中第一个大于等于当前元素的位置,将该位置上的元素替换为当前元素,从而保证子序列仍然是上升的。

最终,子序列的长度就是最长上升子序列的长度。

package main

import (
	"fmt"
	"sort"
)

func main() {
	var n int
	fmt.Scanf("%d", &n)
	a := make([]int, n)
	for i := range a {
		fmt.Scanf("%d", &a[i])
	}
	var dp []int
	for _, x := range a {
		idx := sort.SearchInts(dp, x)
		if idx == len(dp) {
			dp = append(dp, x)
		} else {
			dp[idx] = x
		}
	}
	fmt.Println(len(dp))
}

#牛客春招刷题训练营#
牛客春招刷题训练营 文章被收录于专栏

爱丽姐真是太好了

全部评论

相关推荐

学java时间比较短不到三个月,基本的技术栈都过了一遍就是都不太深,有个小项目。是继续找实习还是沉淀准备秋招呢?找实习的话会花很多时间在八股,放弃的话又怕秋招简历太难看。有无大佬支招
今天java了吗:1.一定要找实习,实习不一定要去,但是找实习过程中的面试经验和心态经验才是最重要的 2.八股本来就是大头,甚至比项目重要 3.这个时间段也是面试比较多的阶段,可以抓住机会锻炼。面试才会发现自己的不足,感觉自己会了和能给面试官娓娓道来是两码事
点赞 评论 收藏
分享
买蜜雪也用卷:我觉得应该没有哪个人敢说自己熟练使用git,代码分支一复杂还是得慢慢寻思一下的,不过基本的拉代码提交代码还有分支什么的是应该会
点赞 评论 收藏
分享
06-12 16:50
已编辑
小米_软件开发(准入职员工)
晓沐咕咕咕:评论区没被女朋友好好对待过的计小将可真多。觉得可惜可以理解,毕竟一线大厂sp。但是骂楼主糊涂的大可不必,说什么会被社会毒打更是丢人。女朋友体制内生活有保障,读研女朋友还供着,都准备订婚了人家两情相悦,二线本地以后两口子日子美滋滋,哪轮到你一个一线城市房子都买不起的996清高计小将在这说人家傻😅
点赞 评论 收藏
分享
06-13 12:13
已编辑
东北大学 射频工程师
26毕业的,日常实习还能找到吗
求实习的青提很想去大厂:目前应该还有hc吧,腾讯感觉还有hc,最近捞了我好几次,因为目前有offer,所以不准备面了,可以再找找,不行的话就找找中小厂试试,因为我之前也找了好久,准备放弃了,结果有个岗位流程特别顺利,然后就oc,只能说坚持下试试,万一呢💪
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务