习题6(leetcode)

88、给定两个有序整数数组 nums1 和 nums2,将 nums2 合并到 nums1 中,使得 num1 成为一个有序数组。
说明:初始化 nums1 和 nums2 的元素数量分别为 m 和 n。你可以假设 nums1 有足够的空间(空间大小大于或等于 m + n)来保存 nums2 中的元素。

解法一:

class Solution {
    public void merge(int[] nums1, int m, int[] nums2, int n) {
        for(int i=0;i<n;i++){              //遍历数组
            nums1[m+i]=nums2[i];       //将nums2中的数放到nums1数的后面形成新数组
        }
        for(int i=1;i<n+m;i++){           //遍历新数组
            int e=nums1[i];             
            int j=i-1;
            while(j>=0&&nums1[j]>e){        //对新数组进行插入排序
                nums1[j+1]=nums1[j];
                j--;
            }
            nums1[j+1]=e;       
        }
    }
}

解法思路:对两个有序数组合并,可以先将小数组的数放进大数组里,然后对大数组进行排序,这种思路比较简单,但是比较费时间。
解法二:

class Solution {
	public void merge(int[] nums1, int m, int[] nums2, int n) {
		int  i = m - 1;                //定义i j k 分别表示两个数组和最终数组的有效元素最大角标
		int j = n - 1; 
		int k = m + n - 1;
		while(i >=0 && j >= 0) {     //当最大角标不为零时对两个数进行判断
			if(nums1[i] > nums2[j]) {
				nums1[k--] = nums1[i--];     //如果数组1大于数组2,将数组1元素放到最后面
			}else {
				nums1[k--] = nums2[j--];      //如果数组2大于数组1,将数组2元素放到最后面
			}
		}
		// 如果j到0,则插入完成
		// 如果j不到0, 则继续插入
		while(j >= 0) {
			nums1[k--] = nums2[j--];
		}
	}
}

解法思路:这种方法采用双指针,首先让i,j,k分别等于数组1,数组2,新数组的最大角标,然后从数组1和数组2 的最大数开始比较,将大的值放入新数组最大角标处,然后角标前移,当j角标为0时表示插入完成,当j不为0 时继续插入。
724、给定一个整数类型的数组 nums,请编写一个能够返回数组“中心索引”的方法。我们是这样定义数组中心索引的:数组中心索引的左侧所有元素相加的和等于右侧所有元素相加的和。如果数组不存在中心索引,那么我们应该返回 -1。如果数组有多个中心索引,那么我们应该返回最靠近左边的那一个。

class Solution {
    public int pivotIndex(int[] nums) {
     if(nums.length<2){     //当数组长度小于2时 则不存在中心索引,返回-1
        return -1;
    }else{
        int sum=0;    //sum表示数组总和
        int left=0;      //表示所有左边数的总和
        for(int j=0;j<nums.length;j++){   //遍历数组求数组的总和
            sum=sum+nums[j];}
        for(int i=0;i<nums.length;i++){       
        	if(i!=0) {
            left=left+nums[i-1];    }      //遍历数组 求左边总和
            if(left==(sum-left-nums[i])){     //左边跟右边进行比较 相等 返回角标 不相等返回-1
                return i;
            }else if(i==nums.length-1){
                return -1;
            }  
        }
        }
    return -1;

    }
}

解题思路:本题求中心索引,即角标对应数的左边总和等于右边总和,对于这道题我们首先可以,用for循环挨个对比左右数字总和判断是否相等,所以这就需要每次循环求出左右数的总和,但是右边数的总和等于总数减去左边数再减去右边数,因为总数是固定的,所有每次只需求出左边数即可得到右边数。
561、给定长度为 2n 的数组, 你的任务是将这些数分成 n 对, 例如 (a1, b1), (a2, b2), …, (an, bn) ,使得从1 到 n 的 min(ai, bi) 总和最大

class Solution {
    public int arrayPairSum(int[] nums) {
        if(nums.length==2){                        //当数组长度为2时 直接输出最小的数
            return Math.min(nums[0],nums[1]);
        }
        for(int i=1;i<nums.length;i++){        //当长度大于2时对数组进行遍历排序
            int e=nums[i];
            int j=i-1;
            while(j>=0&&nums[j]>e){           //当角标j对应的数大于e  则两数交换
                nums[j+1]=nums[j];
                j--;                              //角标j后移 继续比较
            }
            nums[j+1]=e;
        }
        int num=0;
        for(int k=0;k<nums.length;k++){     //排序完成后 将所有偶数位置角标对应的数相加即为结果
            if(k%2==0){
                num+=nums[k];
            }
        }
        return num;
    }
}

解题思路:本题其实是将数组两个两个拆分然后将每个小数组中的小的数字相加。我们可以将整个数字进行排序,然后让第一个和下一个为一组,因为是按顺序排列,所以第一个元素小于或等于第二个,则将所以奇数个元素相加即为最小总和。
167、给定一个已按照升序排列 的有序数组,找到两个数使得它们相加之和等于目标数。函数应该返回这两个下标值 index1 和 index2,其中 index1 必须小于 index2。
说明:返回的下标值(index1 和 index2)不是从零开始的。你可以假设每个输入只对应唯一的答案,而且你不可以重复使用相同的元素。

class Solution {
    public int[] twoSum(int[] numbers, int target) {
        int i=0,j=numbers.length-1;           //创建变量 i和 j分别表示数组最小和最大角标
        while(i<j){                       
            int sum=numbers[i]+numbers[j];  //求最大数和最小数的和
            if(sum==target){
                return new int[]{i+1,j+1};          //如果总和等于目标数则返回这两个角标加一
            }else if(sum<target){
                i++;                             //如果总和小于目标数则最小数对应的角标+1
            }else{
                j--;                          //如果总和大于目标数则最大数对应的角标-1
            }   
        }
        return null;
    }
}

解题思路:对于本题可以使用双指针求解,定义两个指针分别指向数组的前后,然后指针对于位置的数进行求和,若和大于目标数,则后面的指针前移,若小于,则前面指针后移,因为本题值对应唯一答案,所以这个方法总能找到答案。
209、给定一个含有 n 个正整数的数组和一个正整数 s ,找出该数组中满足其和 ≥ s 的长度最小的连续子数组。如果不存在符合条件的连续子数组,返回 0。

class Solution {
    public int minSubArrayLen(int s, int[] nums) {
        int len=0;    //定义初始长度0
        int i=0;       //指针i
        int sum=0;          //总数sum
        for(int j=0;j<nums.length;j++){
            sum=sum+nums[j];                //首先求出总数
            while(sum>=s){                 //如果总数大于目标数
                len=len==0?j-i+1:Math.min(j-i+1,len);           //判断长度len等于j-i+1
                sum=sum-nums[i];           //总数减去角标i对应的数
                i++;
            }
        }
        return len;
    }
}

解题思路:本题也是采用双指针方法,先定义i指针处于数组开始处,然后sum挨个加后面的元素,当sum的值大于目标值时,sum开始减i对应的值,然后i+1,每次sum大于或等于目标值时候记录一次长度,当for循环完成时,输出最小的长度即可。
189、给定一个数组,将数组中的元素向右移动 k 个位置,其中 k 是非负数。

class Solution {
    public void rotate(int[] nums, int k) {
        int n=nums.length;    //定义n为数组的最大长度
        for(int i=1;i<=k;i++){    //循环k次
            int temp=nums[n-1];    //每次循环将最后一个元素给temp
            for(int j=n-1;j>+0;j--){       //后移每个数组
                nums[j]=nums[j-1];
            }
            nums[0]=temp;       //再将最后一个元素放到第一个
        }
    }
}

解题思路:本题其实思路很简单,药师数组右移k个位置,只需每次移动时候将最后一个元素存起来,然后所有元素后移,这样第一个元素就空了,然后将最后一个元素放入第一个,重复k次。
26、给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成

class Solution {
    public int removeDuplicates(int[] nums) {
        int a=1;            //定义长度a为1
        for(int i=0;i<nums.length-1;i++){  //遍历每个元素
            if(nums[i]!=nums[i+1]){       //如果前面元素不等于后面元素
                nums[a]=nums[i+1];	//将后面元素放入a对应位置  
                a++;
            }                           //每次a+1  最后返回a
        }
        return a;
    }
}

解题思路:本题返回的是最终数组长度,首先定义长度a初始化为1,挨个比较每个元素,当第一个元素和后面某个元素不等时,将不相等的元素放入a位置处,然后a处的元素继续跟后面元素对比,如果都相等则输出a如果不等则重负执行此操作。
905、给定一个非负整数数组 A,返回一个数组,在该数组中, A 的所有偶数元素之后跟着所有奇数元素。你可以返回满足此条件的任何数组作为答案。
解法一:

class Solution {
    public int[] sortArrayByParity(int[] A) {
       int[] B=new int[A.length];            //首先定义一个新数组
        int a=0;                                     //指针a为0
        int b=A.length;                        //b为原数组长度
        for(int i=0;i<A.length;i++){             //遍历原数组
            if(A[i]%2==0){
                B[a]=A[i];                    //如果是偶数则存入新数组的开始处
                a++;
            }else{
                B[b-1]=A[i];            //如果是奇数,存入新数组的末尾处
                b--;
            }
        }
        return B;

解法思路:本方法比较简单,但是占用空间大,创建一个新数组对原数组进行判断,如果是奇数则从数组末尾开始存,如果是偶数,则从新数组开头开始存,因为不产生新元素,所以不存在存不下的说法。
解法二:

int a=0,b=A.length-1;                      //定义a为数组开始   b为数组末尾角标
        while(a<b){                              
            while(A[a]%2==0&&a<b){           //  如果a角标对应的数为偶数  则a++
                a++;
            }
            while(A[b]%2!=0&&a<b){              //如果b角标对应的数为奇数  则b--
                b--;
            }
            int temp=A[a];           //否则即为a是奇数b是偶数
            A[a]=A[b];                 //则a,b互换
            A[b]=temp;
            a++;b--;
        }
        return A;

解题思路:本方法非常巧妙,没有新数组,内存占用小。采用双指针弱头指针对应数字为偶数,则指针后移,直到头指针对应数字是奇数时,尾指针同样,若是奇数前移若是偶数和头指针进行交换,使得奇数在后面,偶数在前面。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值