Skip to content

Commit 410b4a6

Browse files
Merge pull request #211 from GitGarden2019/master
第四周算法作业#35
2 parents d6d8089 + 4be8f90 commit 410b4a6

File tree

4 files changed

+284
-0
lines changed

4 files changed

+284
-0
lines changed

Week_04/id_35/Leetcode_169_35.java

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
package com.leecode.week04;
2+
3+
import java.util.Arrays;
4+
import java.util.List;
5+
import java.util.Map;
6+
import java.util.Map.Entry;
7+
import java.util.stream.Collectors;
8+
9+
/**
10+
* 求众数 给定一个大小为 n 的数组,找到其中的众数。众数是指在数组中出现次数大于 ⌊ n/2 ⌋ 的元素。
11+
*
12+
* 你可以假设数组是非空的,并且给定的数组总是存在众数。
13+
*
14+
* @author xuemin.zhu
15+
*/
16+
public class Leetcode_169_35 {
17+
18+
public static void main(String[] args) {
19+
20+
Leetcode_169_35 lc = new Leetcode_169_35();
21+
//System.out.println(lc.majorityElement(new int[]{3, 2, 3}));
22+
System.out.println(lc.majorityElement(new int[]{2, 2, 1, 1, 1, 2, 2}));
23+
System.out.println(lc.majorityElement(new int[]{1}));
24+
System.out.println(lc.majorityElement(new int[]{2,2}));
25+
System.out.println(lc.majorityElement(new int[]{6,5,5}));
26+
27+
}
28+
29+
/**
30+
* Boyer-Moore:
31+
* 思路说明:把所有数据都看成是众数和非众数两类,然后就像玩消消乐那样一个碰一个去抵消掉 这里是不一样的抵消掉
32+
* 因为众数是数量比较多的,把全部非众数灭掉之后还有剩,剩下的就是我们要找的众数了
33+
*/
34+
public int majorityElement(int[] nums) {
35+
36+
//题目中保证要有众数,两个元素的情况只能是两个一样的了
37+
if (nums.length == 1 || nums.length == 2) {
38+
return nums[0];
39+
}
40+
41+
int majorIndex = 0;//首先选择0作为众数
42+
int majorCount = 0;//当前众数的计数个数
43+
for (int i = 0; i < nums.length; i++) {
44+
if (nums[i] == nums[majorIndex]) {
45+
majorCount++;
46+
} else {
47+
majorCount--;
48+
}
49+
50+
if (majorCount == 0) {
51+
//当前众数是0之后需要重新选举新的众数,i 会在经过majorCount时majorCount会变成1
52+
majorIndex = i + 1;
53+
54+
}
55+
}
56+
57+
return nums[majorIndex];
58+
}
59+
60+
61+
/**
62+
* 思路1:最直接的搞法就是先计算出每个数字出现的次数,再看看是不是超过n/2 这里想试试jdk8中新式写法^^
63+
*/
64+
65+
public int majorityElement_v1(int[] nums) {
66+
67+
Map<String, Long> map = Arrays.stream(nums)
68+
.mapToObj(num -> new Tuple(String.valueOf(num), num))
69+
.collect(Collectors.groupingBy(Tuple::getKey, Collectors.counting()));
70+
71+
List<Entry<String, Long>> entrys = map.entrySet().stream()
72+
.filter(s -> s.getValue() > nums.length / 2).collect(Collectors.toList());
73+
74+
if (entrys.isEmpty() || entrys.size() != 1) {
75+
return -1;
76+
}
77+
78+
return Integer.valueOf(entrys.get(0).getKey());
79+
}
80+
81+
static class Tuple {
82+
83+
private String key;
84+
private Integer val;
85+
86+
public Tuple(String key, Integer val) {
87+
this.key = key;
88+
this.val = val;
89+
}
90+
91+
public Integer getVal() {
92+
return val;
93+
}
94+
95+
public void setVal(Integer val) {
96+
this.val = val;
97+
}
98+
99+
public String getKey() {
100+
return key;
101+
}
102+
103+
public void setKey(String key) {
104+
this.key = key;
105+
}
106+
}
107+
}

Week_04/id_35/Leetcode_198_35.java

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package com.leecode.week04;
2+
3+
/**
4+
* 打家劫舍
5+
* 你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。
6+
*
7+
* 给定一个代表每个房屋存放金额的非负整数数组,计算你在不触动警报装置的情况下,能够偷窃到的最高金额。
8+
*
9+
*/
10+
public class Leetcode_198_35 {
11+
12+
public static void main(String[] args) {
13+
Leetcode_198_35 lc=new Leetcode_198_35();
14+
15+
System.out.println(lc.rob(new int[]{1,2,3,1}));
16+
17+
System.out.println(lc.rob(new int[]{2,9,7,3,1}));
18+
19+
20+
}
21+
22+
/**
23+
* 相邻的房间不能偷,转换成我在当前的一套房间的行为
24+
* 1.前一个房间我没有偷,那么当前的房间我可以偷
25+
* 2.前一个房间我是偷了的,当前的房间就不能偷了
26+
* 所以偷到当前的房间的最高金额就是在两种方案中选择最高的
27+
*
28+
* dp[i]=max(dp[i-1]+0),dp[i-2]+num[i]
29+
*
30+
* @param nums
31+
* @return
32+
*/
33+
public int rob(int[] nums) {
34+
int[] dp=new int[nums.length];
35+
36+
if(nums==null||nums.length==0){
37+
return 0;
38+
}
39+
40+
if(nums.length==1){
41+
return nums[0];
42+
}
43+
44+
if(nums.length==2){
45+
return Math.max(nums[0],nums[1]);
46+
}
47+
48+
49+
dp[0]=nums[0];
50+
dp[1]=Math.max(dp[0],nums[1]);//第一次偷了就是dp[0],第一次不偷0+第二次偷num[1],两种情况找个比较大的
51+
52+
for(int i=2;i<nums.length;i++){
53+
dp[i]=Math.max(dp[i-1],dp[i-2]+nums[i]);
54+
}
55+
56+
return dp[nums.length-1];
57+
}
58+
}

Week_04/id_35/Leetcode_213_35.java

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package com.leecode.week04;
2+
3+
/**
4+
* 213. 打家劫舍 II 这次去偷四合院,屋子是连着的 这意味着第一个房屋和最后一个房屋是紧挨着的。同时,相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警
5+
*/
6+
public class Leetcode_213_35 {
7+
8+
9+
10+
public static void main(String[] args) {
11+
Leetcode_213_35 lc=new Leetcode_213_35();
12+
13+
System.out.println(lc.rob(new int[]{2,3,2}));
14+
15+
System.out.println(lc.rob(new int[]{1,2,3,1}));
16+
17+
18+
}
19+
20+
/**
21+
* 思路分析:这个题目是在打家劫舍版本上面首位相连,也就是第一家和最后一家会连着的 那么把情况这两种情况单独拿出来看 1.第一家我可以偷,意味着最后那家就不能偷了
22+
* 2.第一家不偷,最后那家就可以偷 这里的偷和不偷只是要不要纳入本次迭代的考虑范围,求最优解的时候也不一定就一定会要偷
23+
*
24+
* 最后两种方案找个最好的结果就行
25+
*/
26+
public int rob(int[] nums) {
27+
28+
29+
if (nums == null || nums.length == 0) {
30+
return 0;
31+
}
32+
33+
if (nums.length == 1) {
34+
return nums[0];
35+
}
36+
37+
if (nums.length == 2) {
38+
return Math.max(nums[0], nums[1]);
39+
}
40+
41+
42+
int[] dp1=new int[nums.length-1];
43+
44+
dp1[0] = nums[0];
45+
dp1[1] = Math.max(dp1[0], nums[1]);
46+
47+
//可以偷第一家,最后那家的不能偷,循环终止是nums.length-1
48+
for (int i = 2; i < nums.length-1; i++) {
49+
dp1[i] = Math.max(dp1[i - 1], dp1[i - 2] + nums[i]);
50+
}
51+
52+
53+
54+
//可以偷最后一家
55+
int[] dp2=new int[nums.length];
56+
dp2[0]=0;//第一家是强行不能偷
57+
dp2[1]=nums[1];
58+
59+
for (int i=2;i<nums.length;i++){
60+
dp2[i] = Math.max(dp2[i - 1], dp2[i - 2] + nums[i]);
61+
}
62+
63+
64+
return Math.max(dp1[nums.length - 2],dp2[nums.length - 1]);
65+
}
66+
67+
68+
}

Week_04/id_35/Leetcode_70_35.java

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package com.leecode.week04;
2+
3+
/**
4+
* https://leetcode-cn.com/problems/climbing-stairs/ 还是爬楼梯问题,这次换成动态规划的方式来做
5+
*
6+
* 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
7+
*
8+
* 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
9+
*/
10+
public class Leetcode_70_35 {
11+
12+
public static void main(String[] args) {
13+
Leetcode_70_35 lc = new Leetcode_70_35();
14+
System.out.println(lc.climbStairs(1));
15+
System.out.println(lc.climbStairs(2));
16+
System.out.println(lc.climbStairs(3));
17+
System.out.println(lc.climbStairs(4));
18+
System.out.println(lc.climbStairs(6));
19+
System.out.println(lc.climbStairs(8));
20+
System.out.println(lc.climbStairs(20));
21+
22+
}
23+
24+
/**
25+
* 思路分析: 1.楼梯在1阶时候,没得选择,只能是走一步,走法也就是一种 2.楼梯两阶的时候,可以一步+一步或者一次性两步 (1,1) (2)两种 3.楼梯三阶的时候,我们考虑
26+
* 怎样走到3阶的,反正规则就是一次只能走一步或者走两步 a.一次走了一步就到三步了,那么前面就要先走两步了 b.一次走了两步到了三步,那么前面就要走一步
27+
*
28+
* 对任意的N>=3的时候都有这种关系 dp[n]=dp[n-1]+d[n-2],表示的是剩下一步走到N的情况和剩下走两步走到N的情况,所以要走到N步就是前面两者的和
29+
*/
30+
public int climbStairs(int n) {
31+
int oneStep = 1;
32+
int twoStep = 2;
33+
34+
switch (n) {
35+
case 1:
36+
return oneStep;
37+
case 2:
38+
return twoStep;
39+
default:
40+
int[] dp = new int[n];
41+
dp[0] = oneStep;
42+
dp[1] = twoStep;
43+
for (int i = 2; i < n; i++) {
44+
dp[i] = dp[i - 1] + dp[i - 2];
45+
}
46+
return dp[n - 1];
47+
}
48+
49+
50+
}
51+
}

0 commit comments

Comments
 (0)