Arrays 在切片附加中有奇怪的行为

Arrays 在切片附加中有奇怪的行为,arrays,go,append,slice,Arrays,Go,Append,Slice,有人能给我解释一下为什么temp的值在最后一个输出行决定改变,即使temp只是列表数组的一个副本 func子集(nums[]int)[]int{ 如果len(nums)==0{ 返回[][]int{[]int{} } 列表:=[]int{[]int{nums[0]} 对于u,n:=范围nums[1:]{ list=append(list,[]int{n}) 温度:=列表[:len(列表)-1] fmt.Println(温度) 对于u,arr:=范围温度{ arr=append(arr,n) 列表

有人能给我解释一下为什么temp的值在最后一个输出行决定改变,即使temp只是列表数组的一个副本

func子集(nums[]int)[]int{
如果len(nums)==0{
返回[][]int{[]int{}
}
列表:=[]int{[]int{nums[0]}
对于u,n:=范围nums[1:]{
list=append(list,[]int{n})
温度:=列表[:len(列表)-1]
fmt.Println(温度)
对于u,arr:=范围温度{
arr=append(arr,n)
列表=追加(列表,arr)
}
fmt.Println(温度)
格式打印项次(“”)
}
list=append(list,[]int{})
返回列表
}

实际上,您是在复制切片,而不是数组。 切片是数组段的描述符。它由指向数组的指针、段的长度及其容量(段的最大长度)组成。 这意味着,您只需创建切片头的副本。底层数组仍然是共享的。

这是Go中数组和切片的常见问题(与Python和JavaScript中的不同)。你会习惯的,这篇文章已经解释过了


当然,这个解决方案也被解释了,我想你应该知道它是如何工作的


这将使用Go传递(实现起来更简单一些):

同样在Java中

public final class Solution {
    public static final List<List<Integer>> subsets(
        final int[] nums
    ) {
        List<List<Integer>> subs = new ArrayList<>();
        Arrays.sort(nums);
        backtrack(subs, new ArrayList<>(), nums, 0);
        return subs;
    }

    private static void backtrack(
        final List<List<Integer>> subs, 
        final List<Integer> sub, 
        final int[] nums, 
        final int start
    ) {
        subs.add(new ArrayList<>(sub));

        for (int index = start; index < nums.length; index++) {
            sub.add(nums[index]);
            backtrack(subs, sub, nums, index + 1);
            sub.remove(sub.size() - 1);
        }
    }
}

工具书类
  • 有关更多详细信息,请参阅,您可以在其中找到大量解释良好的公认解决方案,包括低复杂度算法和渐近/分析

切片的副本仍然指向相同的底层数组。请阅读此答案,它没有解释为什么它比OP的代码工作得更好/不同,因此它没有用于教育。问题不在于解决挑战,而是关于go切片的一个特性。这个答案根本没有解决这个问题。
func subsets(nums []int) [][]int {
    subs := make([][]int, 0)
    backtrack(nums, 0, nil, &subs)
    return subs
}

func backtrack(nums []int, index int, sub []int, subs *[][]int) {
    if index == len(nums) {
        *subs = append(*subs, append([]int{}, sub...))
        return
    }

    backtrack(nums, index+1, sub, subs)
    backtrack(nums, index+1, append(sub, nums[index]), subs)
}
public final class Solution {
    public static final List<List<Integer>> subsets(
        final int[] nums
    ) {
        List<List<Integer>> subs = new ArrayList<>();
        Arrays.sort(nums);
        backtrack(subs, new ArrayList<>(), nums, 0);
        return subs;
    }

    private static void backtrack(
        final List<List<Integer>> subs, 
        final List<Integer> sub, 
        final int[] nums, 
        final int start
    ) {
        subs.add(new ArrayList<>(sub));

        for (int index = start; index < nums.length; index++) {
            sub.add(nums[index]);
            backtrack(subs, sub, nums, index + 1);
            sub.remove(sub.size() - 1);
        }
    }
}
// The following block might trivially improve the exec time;
// Can be removed;
static const auto __optimize__ = []() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(NULL);
    std::cout.tie(NULL);
    return 0;
}();


// Most of headers are already included;
// Can be removed;
#include <cstdint>
#include <vector>


using ValueType = std::uint_fast16_t;

static const struct Solution {
    static const std::vector<std::vector<int>> subsets(
            const std::vector<int>& nums
    ) {
        std::vector<std::vector<int>> subs = {{}};
        ValueType subs_len;

        for (const auto& num : nums) {
            subs_len = std::size(subs);

            for (ValueType len = 0; len < subs_len; ++len) {
                subs.emplace_back(subs[len]);
                subs.back().emplace_back(num);
            }
        }

        return subs;
    }
};
class Solution:
    def subsets(self, nums):
        return (tuple(j) for i in range(len(nums) + 1) for j in itertools.combinations(nums, i))