7.18 每日学习(三指针,数组)

188 阅读3分钟

合并两个有序数组

题目描述

给你两个按非递减顺序排列的整数数组nums1 和 nums2,另有两个整数 m 和 n ,分别表示 nums1 和 nums2 中的元素数目。

请你合并 nums2 到 nums1 中,使合并后的数组同样按 非递减顺序 排列。

注意:最终,合并后数组不应由函数返回,而是存储在数组 nums1 中。 为了应对这种情况,nums1 的初始长度为 m + n,其中前 m 个元素表示应合并的元素,后 n 个元素为 0 ,应忽略。nums2 的长度为 n 。

  • 示例 1:

输入:nums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3

输出:[1,2,2,3,5,6]

解释:需要合并 [1,2,3] 和 [2,5,6] 。 合并结果是 [1,2,2,3,5,6] ,其中斜体加粗标注的为 nums1 中的元素。

  • 示例 2:

输入:nums1 = [1], m = 1, nums2 = [], n = 0

输出:[1]

解释:需要合并 [1] 和 [] 。 合并结果是 [1] 。

  • 示例 3:

输入:nums1 = [0], m = 0, nums2 = [1], n = 1

输出:[1]

解释:需要合并的数组是 [] 和 [1] 。 合并结果是 [1] 。 注意,因为 m = 0 ,所以 nums1 中没有元素。nums1 中仅存的 0 仅仅是为了确保合并结果可以顺利存放到 nums1 中。

解题思路:

首先这是一道简单题,题意也很清楚,就是将两个数组合并以后,在进行排序。 其中m是num1中不需要变的数,n是num2中需要插入num1中的数。 所以第一版想的是用循环直接插(没想用sort)

func merge(nums1 []int, m int, nums2 []int, n int)  {

    length2 := len(nums2)-1
    total := m+n
    var numbers [total]int 
    for j :=0; j<m ; j++{
        numbers[j]=nums1[j]
    }
    for i :=0 ; i<=length2 ; i++{
        a := i + m
        b := i
        numbers[a]=nums2[b]

    }
    return numbers
}

运行后出现报错信息

`Line 4: Char 5: total declared but not used (solution.go)

Line 5: Char 18: invalid array length total (solution.go)`

查gpt解释:

您遇到的错误是因为 Go 不允许声明长度不是编译时已知的常量值的数组。在您的代码中,数组数字的长度是使用变量 Total 定义的,该变量不是常量。

要解决此问题,您可以使用切片而不是数组。 Go 中的切片更加灵活,并且允许动态调整大小。这是使用切片的代码的更新版本

很明显,因为total是个不定值,所以不能直接初始化,和c++不一样呢。

解决方法为:

	total := m + n
	numbers := make([]int, total)

使用make来创建所需要的空间。

更改完以后本来以为能对来着(

但是运行代码,输入[1,2,3,0,0,0] 3 [2,5,6] 3只会输出[1,2,3,0,0,0],很明显和答案不一样。

显而易见是插拼接出现了问题。

查询原因:

在提供的代码中,您可以使用 make([]int,total) 正确初始化一个名为numbers 的新切片,其具有所需的长度。然后,将 nums1 中的元素复制到前 m 个元素的数字中,这似乎是正确的。

但是,问题出在第二个循环中,您尝试将元素从 nums2 复制到数字中。问题出在行 length2 := len(nums2) - 1 上。通过从长度中减去 1,您将索引移动 1 并且错误地分配了值。

把第二个循环改成:

for i := 0; i < n; i++ {
    a := i + m
    numbers[a] = nums2[i]
}

最后所写的ac代码

最后提交的时候看到了要用nums1输出,悲,写复杂了。最后还是用了sort排序。注意哈,如果像我下面写的一样,注意主函数的写法。

func merge(nums1 []int, m int, nums2 []int, n int)  {

    for i := 0; i < n; i++ {
     a := i + m
     nums1[a] = nums2[i]
    }
    sort.Ints(nums1)
}

在您提供的代码中,函数 merge 没有显式返回任何值。在 Go 中,当函数指定了返回类型,但没有使用 return 语句时,该函数将自动返回该类型的零值。

就您的代码而言,由于合并函数的返回类型是 void 或 ()(无返回值),因此调用该函数不会向调用者提供任何值。该函数将就地修改 nums1 切片,但不会返回新切片或任何其他值。

如果在调用 merge 函数后需要访问修改后的 nums1 切片,则可以直接使用 nums1 切片变量。例如:

nums1 := []int{1, 2, 3, 0, 0, 0}
m := 3
nums2 := []int{2, 5, 6}
n := 3

merge(nums1, m, nums2, n)

// Access the modified nums1 slice
fmt.Println(nums1) // Output: [1 2 3 2 5 6]

这样属于你想输出哪个值,就print出来即可。

有返回值的写法

func merge(nums1 []int, m int, nums2 []int, n int) []int {
    for i := 0; i < n; i++ {
        a := i + m
        nums1[a] = nums2[i]
    }
    return nums1
}

主函数的写法应该变成

func main() {
    nums1 := []int{1, 2, 3, 0, 0, 0}
    m := 3
    nums2 := []int{2, 5, 6}
    n := 3

    merged := merge(nums1, m, nums2, n)
    fmt.Println(merged)
}

很明显由于调用后返回的是nums1,所以直接赋值输出即可

另一种写法:三指针

在此更新的代码中,我使用三个指针:i 代表 nums1,j 代表 nums2,k 跟踪合并数组中的位置。我们从数组的末尾开始比较元素,将较大的元素放在 nums1 的末尾。然后我们移动相应的指针并减少 k。此过程一直持续到 nums1 或 nums2 完全合并为止。最后,如果 nums2 中还有剩余元素,则将它们复制到 nums1 的开头

代码复杂度只有m+n.

func merge(nums1 []int, m int, nums2 []int, n int) {
	i := m - 1
	j := n - 1
	k := m + n - 1

	for i >= 0 && j >= 0 {
		if nums1[i] > nums2[j] {
			nums1[k] = nums1[i]
			i--
		} else {
			nums1[k] = nums2[j]
			j--
		}
		k--
	}

	for j >= 0 {
		nums1[k] = nums2[j]
		j--
		k--
	}
}

我写了这两种解答以后,再去看看官方解答。

官方解答:直接合并后排序

这个算是我的第一种写法,不过直接用copy。简单很多,我不太熟悉这些操作,悲。

func merge(nums1 []int, m int, nums2 []int, _ int) {
    copy(nums1[m:], nums2)
    sort.Ints(nums1)
}

作者:LeetCode-Solution
链接:https://leetcode.cn/problems/merge-sorted-array/solution/he-bing-liang-ge-you-xu-shu-zu-by-leetco-rrb0/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

官方解答方法二:双指针

方法一没有利用数组nums1与nums2已经被排序的性质。为了利用这一性质,我们可以使用双指针方法。这一方法将两个数组看作队列,每次从两个数组头部取出比较小的数字放到结果中。 代码如下:

func merge(nums1 []int, m int, nums2 []int, n int) {
    sorted := make([]int, 0, m+n)
    p1, p2 := 0, 0
    for {
        if p1 == m {
            sorted = append(sorted, nums2[p2:]...)
            break
        }
        if p2 == n {
            sorted = append(sorted, nums1[p1:]...)
            break
        }
        if nums1[p1] < nums2[p2] {
            sorted = append(sorted, nums1[p1])
            p1++
        } else {
            sorted = append(sorted, nums2[p2])
            p2++
        }
    }
    copy(nums1, sorted)
}

作者:LeetCode-Solution
链接:https://leetcode.cn/problems/merge-sorted-array/solution/he-bing-liang-ge-you-xu-shu-zu-by-leetco-rrb0/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

他的大概思路就是,先创建一个空数组sort,然后将nums1,nums2中的数排序,最后将俩个数比较,插入小的。 其实,emmm,感觉有一说一不如三指针。