Array(3) -- Merge Sorted Array, Search in Rotated Sorted Array I, II, Triangle, Subsets II

本文介绍了数组相关的几种算法实现,包括合并两个已排序数组、在旋转排序数组中搜索目标值及其变种问题、求解三角形路径最小和,以及生成包含重复元素集合的所有子集。这些算法覆盖了从简单到复杂的多种数据结构操作与搜索技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Merge Sorted Array

Given two sorted integer arrays nums1 and nums2, merge nums2 into nums1 as one sorted array.

Note:
You may assume that nums1 has enough space (size that is greater or equal to m + n) to hold additional elements from nums2. The number of elements initialized in nums1 and nums2 are m and n respectively.


和pascall triangle相似的思路,不过这次空间已经开好了。后方空间是空闲的,所以从后向前进行处理,可以避免先处理前面导致需要空间交换。


    void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {  
        int i = m - 1, j = n - 1;
        int k = m + n - 1;
        while (i > -1 && j > -1){
            if (nums1[i] > nums2[j]) nums1[k--] = nums1[i--];
            else nums1[k--] = nums2[j--];
        }
        while (i > -1) nums1[k--] = nums1[i--];
        while (j > -1) nums1[k--] = nums2[j--];
    }  


Search in Rotated Sorted Array


解法1:基本思想是二分查找,首先利用二分查找找到最小值的位置,然后将数组看做是平移之后的,

数组整体向右移了minIndex个单位,数组[(i+minIndex)%n]是非rotated且有序的,left,right可以看做是index

关于left/right是half+-1还是half,用相邻的数模拟临界值试一下就好了。

    int search(vector<int>& nums, int target) {
    	int left = 0;
     int right=nums.size() - 1;
    	int half = 0;
    	int minIndex = 0;
    	while (left < right){   //能找到左边界,所以left可以half+1
    		half =(left + right) / 2;
    		if (nums[half] > nums[right])
    			left = half+1;
    		else
    			right = half;
    	}
    	minIndex = left;
    	left = 0;
    	right = nums.size() - 1;
    	int realHalf = 0;
        while (left <= right){
            half = (left + right)/2;
            realHalf = (half + minIndex) % nums.size();  //
            if(nums[realHalf] == target) return realHalf;
            if(nums[realHalf] > target)
                right = half - 1;
            else
                left = half + 1;
        }
    	return -1;
    }


解法2:

对于rotated array来说,比如[4,5,6,7,1,2,3],一定有一部分是有序的,如果target在有序的那一部分,那么可以在那一部分进行二分查找;如果不在,则丢到另一部分中寻找,最后一定可以找到target处于某有序的部分。 

    int search(vector<int>& nums, int target) {
        int lo = 0, hi = nums.size() - 1;
        int mid = 0;
        while (lo < hi){
              mid = (lo + hi) / 2;
              if (nums[mid] == target) return mid;
              if (nums[mid] > nums[hi]){	
                  if (nums[mid] > target && nums[lo] <= target) hi = mid;	//target在有序的部分
                  else lo = mid + 1;
              }else if (nums[mid] < nums[hi]){
                  if (nums[mid] < target && nums[hi] >= target) lo = mid + 1;	//target在有序的部分
                  else hi = mid;
              }
        }
        return nums[lo] == target ? lo : -1;
    }



Search in Rotated Sorted Array II

Follow up for "Search in Rotated Sorted Array":
What if duplicates are allowed?

Would this affect the run-time complexity? How and why?

这个和上一道题的区别在于当两个数相同时,比如 nums[mid] = nums[hi]时,不能说明mid和hi指针相同,需要移动直到两者不等。

此时如果采用解法1的变体,需要改写两段二分查找,虽然可行,但是代码量稍多


        int lo = 0, hi = nums.size() - 1;  
        int mid = 0;  
        while (lo < hi){  
              mid = (lo+hi)/2;  
              if (nums[mid] == target) return true;  
              if (nums[mid] > nums[hi]){  
                  if (nums[mid] > target && nums[lo] <= target) hi = mid;  
                  else lo = mid + 1;  
              }else if (nums[mid] < nums[hi]){  
                  if (nums[mid] < target && nums[hi] >= target) lo = mid + 1;  
                  else hi = mid;  
              }else  
                hi--;  
        }  
        return nums[lo] == target ? true : false;  



Triangle

Given a triangle, find the minimum path sum from top to bottom. Each step you may move to adjacent numbers on the row below.

For example, given the following triangle

[
     [2],
    [3,4],
   [6,5,7],
  [4,1,8,3]
]

The minimum path sum from top to bottom is 11 (i.e., 2 + 3 + 5 + 1 = 11).


感觉思想也属于dp。用一个vector存储每一行,包含该行每个数的最短路径是多少,vector进行循环使用,因为只有上一行的状态是有用的,最后一行统计vector中最小的。

空间复杂度O(n)


    int minimumTotal(vector<vector<int>>& triangle) {
        int n = triangle.size();
        vector<int> dp(n, 0);
        dp[0] = triangle[0][0];
        for (int k = 1; k < n; k++){
            dp[k] = dp[k-1] + triangle[k][k];
            for (int i = k - 1; i > 0; i--){	//一定是从后往前,不然会有影响
                dp[i] = triangle[k][i] + min(dp[i], dp[i-1]);
            }
            dp[0] += triangle[k][0];
        }
        int rst = INT_MAX;
        for (int minT : dp)
            rst = min(rst, minT);
        return rst;
    }


Subsets II

Given a collection of integers that might contain duplicates, nums, return all possible subsets.

Note: The solution set must not contain duplicate subsets.

对于没有重复数字的子集,有2^n个,即每个数字出现或不出现;对于重复出现的数字,看做一个特殊数字,特殊数字出现1次、2次或n次。

vector<vector<int> > subsetsWithDup(vector<int> &S) {
        vector<vector<int> > totalset = {{}};
        sort(S.begin(),S.end());
        for(int i=0; i<S.size();){
            int count = 0; // num of elements are the same
            while(count + i<S.size() && S[count+i]==S[i])  count++;
            int previousN = totalset.size();
            for(int k=0; k<previousN; k++){
                vector<int> instance = totalset[k];
                for(int j=0; j<count; j++){
                    instance.push_back(S[i]);
                    totalset.push_back(instance);
                }
            }
            i += count;
        }
        return totalset;
        }


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值