offer_1
前言:
因为实在是太菜了,所以先刷剑指offer,然后暴力永远的神
1.二维数组中的查找
题目描述
题目分析:
这个题目应该有多种思路来解决,
其中最容易想到的是暴力.直接遍历整个数组,然后寻找相似项.如果存在相似项则返回true,不存在相似项返回false.
但是如果这样写的话,就没有利用题目的条件,面试也可能到此为止了.
可以利用题目条件,使用线性查找的方法.
方法一:暴力
func findNumberIn2DArray(matrix [][]int, target int) bool {
num:=make(map[int]bool)
for i:=0;i<len(matrix);i++{
for j:=0;j<len(matrix[0]);j++ {
num[matrix[i][j]] = true
}
}
_,ok := num[target]
return ok
}
因为这两天补习了一下map的相关知识,所以下意识就使用了map的特性进行解题.
思路很简单:将所有的数据存储到map中,然后判断map中是否存在指定数.
一般来说,如果使用暴力法,应该直接遍历,使用map的话比较占用内存.
这种方法执行用时比较长(又不是不能用)
方法二线性查找:
这是比较推荐的一种方法,充分利用了题目的条件.
先分析思路:
根据官方题解:
由于给定的二维数组具备每行从左到右递增以及每列从上到下递增的特点,当访问到一个元素时,可以排除数组中的部分元素。
利用这个二维数组的特性,在每次查找的时候都可以把一部分的元素排除.
从右上角出发,依次遍历,每次都可以排除元素
func findNumberIn2DArray(matrix [][]int, target int) bool {
if len(matrix) == 0 {
return false
}
i, j := 0, len(matrix[0]) - 1
for i < len(matrix) && j >= 0 {
if matrix[i][j] == target {
return true
} else if matrix[i][j] < target {
i++
} else {
j--
}
}
return false
}
2. 0~n-1中缺失的数字
题目描述:
思路分析
因为这个是一个递增的排序数组,那首先就应该想到使用二分法进行解题.
根据题意,数组可以按照以下规则划分为两部分。
左子数组: nums[i] =i ;
右子数组: nums[i] != i ;
分析题目可以发现:缺失的数字等于右子数组的首位元素对应的索引,因此考虑使用二分法查找右子数组的首位元素.
解法一:暴力
虽然很low,但是暴力也是一种解法,通过遍历可以直接找到右子树的下标
func missingNumber(nums []int) int {
size := len(nums)
for i:=0; i<size; i++ {
if nums[i] != i {
return i
}
}
return size
}
在这道题中,暴力解法效果还行
解法二:二分查找
func missingNumber(nums []int) int {
left,right := 0, len(nums)-1
for left <= right {
mid := left + (right-left)/2
if nums[mid] == mid {
left = mid + 1
}else{
right = mid - 1
}
}
return left
}
速度和暴力差不多
解法三:按位异或
func missingNumber(nums []int) int {
n := len(nums)
for k:= range nums{
n ^= k ^ nums[k]
}
return n
}
看了"sakura-151"的题解,我发现这个解法,非常的巧妙,解释如下:
^= 位逻辑异或赋值,是一个复合赋值运算符
异或就是两个数的二进制形式,按位对比,相同则取0。
0^0→0 , 0^1→1 , 1^0→1 , 1^1→0
任何数与0异或等于它本身,即a^0=a
一个数与自己异或结果为0,即a^a=0
令0~n的数与nums中的数异或,运算中除了缺失值只出现一次外,其他数都出现两次等同于与自身异或。
3. 在排序数组中查找数字
题目描述:
方法一:暴力
暴力或许会迟到,但永远不会缺席.对于我这样的小白来说,暴力是最容易想到的.虽然不应该经常暴力法,但是在学的过程中,应该尽可能地把想法全部实现.
func search(nums []int, target int) int {
sum:=0
for _,i :=range nums{
if i == target{
sum++
}
}
return sum
}
效果还行
方法二:二分查找
因为这个是一个排序数组,所以另一个可以快速想到的方法就是二分查找.
考虑到会有多个数与target相同,先使用二分查找寻找最左边的与target数值相等的数,然后再使用二分查找寻找到最右边与target相等的数,left-right就是结果
func search(nums []int, target int) int {
left := sort.SearchInts(nums, target)
if left == len(nums) || nums[left] != target {
return 0
}
right := sort.SearchInts(nums, target + 1)
return right - left
}
这一次,暴力法全胜.
4.左旋转字符串
题目描述
题目分析
这题非常简单,没啥好讲的,就是吧指定的字符放到字符串的前端就好.
使用go的话,一行就可以得出结果:
func reverseLeftWords(s string, n int) string {
return s[n:]+s[:n]
}
5.复杂链表的复制
题目描述
题目分析
看到这个题目我最先想到的是一种偷懒的方法:
func copyRandomList(head *Node) *Node {
return head
}
但是结果却是:
看来我被官方拿捏的死死的.
既然不能偷懒,那就好好分析:
这个题目的意思还是有点难理解的.
官方题解的介绍如下:
如果是普通链表,我们可以直接按照遍历的顺序创建链表节点。而本题中因为随机指针的存在,当我们拷贝节点时,「当前节点的随机指针指向的节点」可能还没创建
一个可行方案是,我们利用回溯的方式,让每个节点的拷贝操作相互独立。对于当前节点,我们首先要进行拷贝,然后我们进行「当前节点的后继节点」和「当前节点的随机指针指向的节点」拷贝,拷贝完成后将创建的新节点的指针返回,即可完成当前节点的两指针的赋值。
具体地,我们用哈希表记录每一个节点对应新节点的创建情况。遍历该链表的过程中,我们检查「当前节点的后继节点」和「当前节点的随机指针指向的节点」的创建情况。如果这两个节点中的任何一个节点的新节点没有被创建,我们都立刻递归地进行创建。当我们拷贝完成,回溯到当前层时,我们即可完成当前节点的指针赋值。注意一个节点可能被多个其他节点指向,因此我们可能递归地多次尝试拷贝某个节点,为了防止重复拷贝,我们需要首先检查当前节点是否被拷贝过,如果已经拷贝过,我们可以直接从哈希表中取出拷贝后的节点的指针并返回即可。
func deepCopy(node *Node) *Node {
if node == nil {
return nil
}
if n, has := cachedNode[node]; has {
return n
}
newNode := &Node{Val: node.Val}
cachedNode[node] = newNode
newNode.Next = deepCopy(node.Next)
newNode.Random = deepCopy(node.Random)
return newNode
}
func copyRandomList(head *Node) *Node {
cachedNode = map[*Node]*Node{}
return deepCopy(head)
}
ERROR: Repository not found.
fatal: Could not read from remote repository.
Please make sure you have the correct access rights
and the repository exists.
FATAL {
err: Error: Spawn failed
at ChildProcess. (D:\CodeLife\root\blog\node_modules\hexo-util\lib\spawn.js:51:21)
at ChildProcess.emit (node:events:390:28)
at ChildProcess.cp.emit (D:\CodeLife\root\blog\node_modules\cross-spawn\lib\enoent.js:34:29)
at Process.ChildProcess._handle.onexit (node:internal/child_process:290:12) {
code: 128
}
} Something’s wrong. Maybe you can find the solution here: %s https://hexo.io/docs/troubleshooting.html