动态数组练习题(三)

88. 合并两个有序数组

给定两个有序整数数组 nums1 和 nums2,将 nums2 合并到 nums1 中,使得 num1 成为一个有序数组。

说明:

初始化 nums1 和 nums2 的元素数量分别为 m 和 n。
你可以假设 nums1 有足够的空间(空间大小大于或等于 m + n)来保存 nums2 中的元素。
示例:

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

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

解析:

1.将nums2的元素往nums1中存
   nums1的有效元素个数为 index1 = m-1    
   nums1的总长度为 index = m+n-1      
   nums2的长度为  index2 = n-1           

2.nums1和nums2从后向前比较
   如果nums1[index1] > nums2[index2],则nums1[index--]=nums1[index1--]
   如果nums1[index1] <= nums2[index2],则nums1[index--]=nums2[index2--]
   当index1<0或者index2<0时循环结束
   当index2<0时,说明nums2中的元素已经全部加入nums1
   当index1<0时,idenx2>=0时直接将nums2中的元素遍历到nums1中


	public void merge(int[] nums1, int m, int[] nums2, int n) {
        int index=m+n-1;
        int index1=m-1;
        int index2=n-1;
        
        while(true){
        	if(index1<0||index2<0){//跳出循环
        		break;
        	}
        	if(nums1[index1]>=nums2[index2]){
        		nums1[index--]=nums1[index1--];
        	}else{
        		nums1[index--]=nums2[index2--];
        	}
        }
        if(index2>=0){
        	for(int i=0;i<=index2;i++){
        		nums1[i]=nums2[i];
        	}
        }
    }

35. 搜索插入位置

给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。

你可以假设数组中无重复元素。

示例 1:

输入: [1,3,5,6], 5
输出: 2
示例 2:

输入: [1,3,5,6], 2
输出: 1
示例 3:

输入: [1,3,5,6], 7
输出: 4
示例 4:

输入: [1,3,5,6], 0
输出: 0

解析:排序数组,有目标值,类似于二分查找
1.二分查找 low high mid
2.两种特殊情况: ①查找在low   ②查找在high   
3.正常情况下,查找的元素和mid比较,看在哪边

如果元素=mid时,return mid
如果元素<mid在左,high=mid-1 mid=(low+high)/2
如果元素>mid在右,low=mid+1 mid=(low+high)/2
这就是二分查找
4.当low>high时 没有找到  将元素插入low的位置

public int searchInsert(int[] nums, int target) {
        int low=0;
        int high=nums.length-1;
        int mid=(low+high)/2;
        //判断nums是否为空
        if(nums==null||nums.length==0){
        	return 0;
        }
        //判断查找的元素在low
        if(nums[low]==target){
        	return low;
        }
        //判断查找的元素在high
        if(nums[high]==target){
        	return high;
        }
        //当low<=high继续查找,负责没有查到
        while(low<=high){
        	//判断查找的元素在mid
        	if(nums[mid]==target){
        		return mid;
        	}
        	//右边
        	if(nums[mid]<target){
        		low=mid+1;
        	}else{//左边
        		high=mid-1;
        	}
        	mid=(low+high)/2;
        }
        return low;
    }

66. 加一

给定一个由整数组成的非空数组所表示的非负整数,在该数的基础上加一。

最高位数字存放在数组的首位, 数组中每个元素只存储单个数字。

你可以假设除了整数 0 之外,这个整数不会以零开头。

示例 1:

输入: [1,2,3]
输出: [1,2,4]
解释: 输入数组表示数字 123。
示例 2:

输入: [4,3,2,1]
输出: [4,3,2,2]
解释: 输入数组表示数字 4321。

解析:根据题意,加1,有可能产生进制,例如[1,2,9] + 1 = [1,3,0]。当9+1产生进位,存0进去 ,我们可以用(digits[x]+1)%10来判断,那怎么知道是否有进位呢?可以用(digits[x]+1)/10判断,等于10时说明就有进位产生。当然我们也有特殊情况,999+1 变成4位数,[9,9,9] + 1 = [1,0,0,0],定义一个进位carry,来判断当前是不是999,如果carry最后等于1,说明是999
 


	public int[] plusOne(int[] digits) {
		int carry=1;//进位
		int num=0;
		//从数组最后一位开始计算
		for(int i=digits.length-1;i>=0;i--){
			num=digits[i]+carry;
			digits[i]=num%10;//超出10,用取余取出个位存进去
			carry=num/10;//num=10,证明产生进位
			//无进位
			if(carry==0){
				break;
			}
		}
		//循环跳出后,carry==1证明是999+1的情况
		if(carry==1){
			int[] arr = new int[digits.length+1];//创建一个长度为digits.length+1新数组
			arr[0]=1;
			return arr;
		}
		return digits;
	}

20. 有效的括号

给定一个只包括 '(',')','{','}','[',']' 的字符串,判断字符串是否有效。

有效字符串需满足:

左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
注意空字符串可被认为是有效字符串。

示例 1:

输入: "()"
输出: true
示例 2:

输入: "()[]{}"
输出: true
示例 3:

输入: "(]"
输出: false
示例 4:

输入: "([)]"
输出: false
示例 5:

输入: "{[]}"
输出: true

解析:根据题意,我们可以用栈进行判断。将字符串拆分存进数组中,首先判断栈是否为空,如果为空直接存进去;如果不为空,先将其与栈顶元素进行比较,相匹配的符号之间相差-1或-2( top-c ==-1 || top-c==-2),如果匹配将栈顶元素出栈,如果不匹配入栈。

public boolean isValid(String s) {
		//创建一个栈
        Stack<Character> stack = new Stack<Character>();
        //将字符串中的字符拆开放入栈中
        for(int i=0;i<s.length();i++){
        	char c = s.charAt(i);
        	//判断栈是否为空
        	if(stack.isEmpty()){
        		stack.push(c);//将字符入栈
        	}else{//不为空
        		char top = stack.peek();//获取栈顶元素
        		if(top-c==-1 || top-c==-2){//判断是否匹配
        			stack.pop();//将栈顶出栈
        		}else{
        			stack.push(c);//将c入栈
        		}
        	}
        }
        return stack.isEmpty();
}

240. 搜索二维矩阵 II

编写一个高效的算法来搜索 m x n 矩阵 matrix 中的一个目标值 target。该矩阵具有以下特性:

每行的元素从左到右升序排列。
每列的元素从上到下升序排列。
示例:

现有矩阵 matrix 如下:

[
  [1,   4,  7, 11, 15],
  [2,   5,  8, 12, 19],
  [3,   6,  9, 16, 22],
  [10, 13, 14, 17, 24],
  [18, 21, 23, 26, 30]
]
给定 target = 5,返回 true。

给定 target = 20,返回 false。

解析:我们可以根据时间的复杂度进行解题。当从每一行进行二分查找时,时间复杂度为O(mlogn);当从左上和右下开始查找时,方向无法确定;当从左下角的位置开始查询,时间复杂度为O(m+n);由此我们可以选择从左下角的位置开始查找。那什么时候找不到呢?当查到右上角的时候,如果比它小往上走,如果比它大往右走,此时我们会发现它已经走出去了,说明没有找到该元素。

public boolean searchMatrix(int[][] matrix, int target) {
		//1.数组对象压根就没有
        //2.对象有,没数据
        //3.对象有,有行,行中无元素
        if(matrix==null||matrix.length==0||matrix[0].length==0){
        	return false;
        }
        int row=matrix.length; //行
        int col=matrix[0].length; //列
        //左下角的位置
	int x=row-1;
        int y=0;
        while(true){
        	if(x<0||y>=col){//没有找到
        		return false;
        	}
        	if(matrix[x][y]<target){
        		y++;
        	}else if(matrix[x][y]>target){
        		x--;
        	}else{
        		return true;
        	}
        }
    }

209. 长度最小的子数组

给定一个含有 n 个正整数的数组和一个正整数 s ,找出该数组中满足其和 ≥ s 的长度最小的连续子数组。如果不存在符合条件的连续子数组,返回 0。

示例: 

输入: s = 7, nums = [2,3,1,2,4,3]
输出: 2
解释: 子数组 [4,3] 是该条件下的长度最小的连续子数组。

解析:根据题意,我们可以利用滑窗机制,用两个指针对数组进行动态变化。先将第一个数放入窗口,加入第二个数,然后跟目标值进行对比,如果s大的话,继续往里加数,当大于等于s时候,记录窗口中的长度,然后将前面先进的数减掉,再跟s比较,如果大于等于s的话,再减掉前的数,等到减到小于s的时候,再往里加数,重复上述操作,然后得出长度最小的连续数组。

public int minSubArrayLen(int s, int[] nums) {
		//判断nums是否为空或nums中有无元素
		if(nums==null || nums.length==0){
			return 0;
		}
		int len=0;//记录长度
		int sum=0;//记录和
        int i=0;
        for(int j=0;j<nums.length;j++){
        	sum+=nums[j];//往进加数字
        	while(sum>=s){
        		//当len=0时,j-i+1
        		//当len!=0时,len和j-i+1比较,谁小取谁
        		len=len==0?j-i+1:Math.min(len, j-i+1);
        		sum-=nums[i++];//往出减数字
        	}
        }
        return len;
    }

54. 螺旋矩阵

给定一个包含 m x n 个元素的矩阵(m 行, n 列),请按照顺时针螺旋顺序,返回矩阵中的所有元素。

示例 1:

输入:
[
 [ 1, 2, 3 ],
 [ 4, 5, 6 ],
 [ 7, 8, 9 ]
]
输出: [1,2,3,6,9,8,7,4,5]
示例 2:

输入:
[
  [1, 2, 3, 4],
  [5, 6, 7, 8],
  [9,10,11,12]
]
输出: [1,2,3,4,8,12,11,10,9,5,6,7]

解析:首先我们根据题意得出,只有向右、向下、向左、向上这个四种情况。

向右:detX=0 delY=1

向下:detX=1 delY=0

向左:detX=0 delY=-1

向上:detX=-1 delY=0

deltX={0,1,0,-1}
deltY={1,0,-1,0}

public List<Integer> spiralOrder(int[][] matrix) {
        ArrayList<Integer> list = new ArrayList<Integer>();
        if(matrix==null||matrix.length==0||matrix[0].length==0){
        	return list;
        }
        int x=0;
        int y=0;
        int R=matrix.length;
        int C=matrix[0].length;
        boolean[][] visited = new boolean[R][C];
        int[] deltX={0,1,0,-1};
        int[] deltY={1,0,-1,0};
        int dir=0;
        for(int i=0;i<R*C;i++){
        	list.add(matrix[x][y]);
        	visited[x][y]=true;
        	int nx=x+deltX[dir];
        	int ny=y+deltY[dir];
        	if(nx>=0&&nx<R&&ny>=0&&ny<C&&!visited[nx][ny]){
        		x=nx;
        		y=ny;
        	}else{
        		dir=(dir+1)%4;
        		x+=deltX[dir];
        		y+=deltY[dir];
        	}
        }
        return list;
    }

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值