leetcode刷题记录(961、682)

2018.12.24 leetcode 刷题总结

题号:961

在大小为 2N 的数组 A 中有 N+1 个不同的元素,其中有一个元素重复了 N 次。
返回重复了 N 次的那个元素。

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

我的想法:

  1. 先对数组排序,排序后的数组中出现N次的数字一定位置相邻
  2. 从头遍历数组,用临时变量与数组中的元素值相比较,若相同则返回该值;若不相同,将数组元素的值赋给临时变量
  3. 遍历时不必遍历整个数组,由于排序的原因,只遍历数组长度的一半加一个元素即可

对应程序:

// java
class Solution {
    public int repeatedNTimes(int[] A) {
    	// 排序
		Arrays.sort(A);
		// 临时变量,初始化为数组第一个元素的值
		int temp = A[0];
		// 遍历数组,注意下标范围[1, A.length/2]
		for(int i = 1; i < A.length/2 + 1 ; ++i) {
			if(temp == A[i]) {
				return temp;
			}else {
				temp = A[i];
			}
		}
		// 若前面的N项都不相等,则后面的N项一定都是相等的
        return A[A.length/2];
    }
}

优化:

由于是新题,没有图表可以参考,看过评论后发现一种不用循环比较的办法:

程序:
// java
class Solution {
    public int repeatedNTimes(int[] A) {
		Arrays.sort(A);
		
        return A[A.length/2] == A[A.length - 1]?A[A.length/2]:A[A.length/2 - 1];
    }
}

由于出现N次的数字在经过数组排序后是相邻的,而且他们的长度是数组的一半,因此,若A[A.length - 1]A[A.length/2] 这个两个值是相同的,说明整个数组的后半段都是相同的数字,前半段都是不同的;若不相同时,说明这个数是出现在 [0, A.length - 2] 的范围中的,这个范围的长度是A.length - 1,由于出现N次的数字长度是 A.length/2,因此可以保证,无论这组相同的数字的出现的范围是什么,在数组中下标为 (A.length - 2)/2的数字一定是出现N次的这个数字

如图:

以长度为6的数组为例
因此,还有一种和A[0]比较的方法,想法和上面相同

程序:
// java
class Solution {
    public int repeatedNTimes(int[] A) {
		Arrays.sort(A);
        return A[0] == A[A.length/2 - 1]?A[0]:A[A.length/2];
    }
}

题号:682

你现在是棒球比赛记录员。
给定一个字符串列表,每个字符串可以是以下四种类型之一:
1.整数(一轮的得分):直接表示您在本轮中获得的积分数。
2."+"(一轮的得分):表示本轮获得的得分是前两轮有效 回合得分的总和。
3.“D”(一轮的得分):表示本轮获得的得分是前一轮有效 回合得分的两倍。
4.“C”(一个操作,这不是一个回合的分数):表示您获得的最后一个有效 回合的分数是无效的,应该被移除。
每一轮的操作都是永久性的,可能会对前一轮和后一轮产生影响。
你需要返回你在所有回合中得分的总和。

输入: [“5”,"-2",“4”,“C”,“D”,“9”,"+","+"]
输出: 27
解释:
第1轮:你可以得到5分。总和是:5。
第2轮:你可以得到-2分。总数是:3。
第3轮:你可以得到4分。总和是:7。
操作1:第3轮的数据无效。总数是:3。
第4轮:你可以得到-4分(第三轮的数据已被删除)。总和是:-1。
第5轮:你可以得到9分。总数是:8。
第6轮:你可以得到-4 + 9 = 5分。总数是13。
第7轮:你可以得到9 + 5 = 14分。总数是27。

我的想法:

  1. 首先想到的数据结构就是,题目中定义的操作无非是对栈顶元素操作的扩展
  2. 遍历string数组,对应不同的元素进行不同的操作,将原始值和中间的结果统统入栈
  3. 遍历栈,得到结果

对应程序:

// java
class Solution {
    public int calPoints(String[] ops) {
    	// LinkedList可充当栈结构
        LinkedList<Integer> stack = new LinkedList<>();
        for(String op : ops) {
        	// 匹配数字,入栈
        	if(op.matches("^-?[0-9]+$")) {
        		stack.addFirst(Integer.valueOf(op));
        	}
        	// 移除栈顶元素
        	if(op.equals("C")) {
        		stack.removeFirst();
        	}
        	// 栈顶元素乘2的结果入栈
        	if(op.equals("D")) {
        		Integer top = stack.getFirst();
        		// 可能存在结果溢出
        		stack.addFirst(top * 2);
        	}
        	// 计算位于栈顶的前两个元素,将结果入栈
        	if(op.equals("+")) {
        		Integer temp1 = stack.removeFirst();
        		Integer temp2 = stack.getFirst();
        		Integer temp3 = temp1 + temp2;
        		stack.addFirst(temp1);
        		stack.addFirst(temp3);
        	}
        }
        
        int result = 0;
        // 遍历栈
        for(Integer num : stack) {
        	result += num;
        }
        
		return result;
    }
}

优化

LinkedList底层的数据结构是基于双向循环链表的,因此遍历它会非常的费时,我们考虑用数组来实现,并且将if…else的判断换成switch…case的方式

程序:
// java
class Solution {
    public int calPoints(String[] ops) {
		int index = -1;
		int[] stack = new int[ops.length];
		for(String str : ops) {
			switch(str) {
			case "C" :
				// 相当于删除元素
				stack[index] = 0;
				// 指针前移
				index--;
				break;
			case "D" :
				// 计算要填充到数组中的值
				int mul = stack[index] * 2;
				// 指针后移
				index++;
				// 写入数组
				stack[index] = mul;
				break;
			case "+" :
				// 计算下标最大的两个元素的和
				int sum = stack[index] + stack[index-1];
				// 指针右移
				index++;
				// 写入数组
				stack[index] = sum;
				break;
			// 其他情况,即为数字时
			default :
				// 一定是将数字添加到数组中的操作,先右移指针
				index++;
				// 写入数组
				stack[index] = Integer.parseInt(str);
				break;
			}
		}
		
		int result = 0;
		// 遍历数组计算结果
		for(int num : stack) {
			result += num;
		}
		
		return result;
    }
}

说明:以上程序是指针始终指向数组最后一个元素,因此在将新的元素写入数组时,先进行指针右移的操纵,再写入值,这也是为什么下标的初始值是-1

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值