文章目录
代码源OJ
101特殊的正方形
输入n,输出n行n列的由+
和.
组成的正方形,其中最外面一圈全是+
,第二圈全是.
,…,对于第ii圈,如果ii是奇数,那么全是+
,否则全是.
。
先赋值再输出, 根据圈数n, 进行n次赋值, 每次进行一层
赋完这一圈后,两个变量向中心收缩(l++,r–)
import java.util.Scanner;
public class main {
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
char[][] f=new char[110][110];
int n=sc.nextInt();
int m=n;
int up=0,l=0,r=n-1,down=n-1;
char s[]={'+','.'};
while(m>=0){
char c=s[l%2];
for (int i = 0; i < m; i++) {
f[l+i][r]=c;
f[l+i][l]=c;
f[l][l+i]=c;
f[r][l+i]=c;
}
l++;
r--;
m-=2;
}
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
System.out.print(f[i][j]);
}
System.out.println("");
}
}
}
102走楼梯2
楼梯有 n 阶,上楼可以一步上一阶,也可以一步上二阶。
但你不能连续三步都走两阶,计算走到第n阶共有多少种不同的走法
和正常的走楼梯问题不同点是不能连续走3次两阶,所以开一个N*3的二维数组
012标示三种状态(连续走了几次两阶)
f[1] [j]因为最后一步走的是2,所以就等于上上层的f[0] [j-2](因为最后一步是走了一次两步,所以只能通过上上层走一次两步得到,而因为最后一步只连续走了一次两步,所以只能通过f[0]得到,如果是f[1],最后一步再走一次两部就会变成f[2]),f[2] [j]因为最后一次走了两次两部,所以可以通过上上层的f[1] [j-2]得到(道理同上)
import java.util.Scanner;
public class main {
public static void main(String[] args) {
long[][] f=new long[3][110];
Scanner sc=new Scanner(System.in);
int n=sc.nextInt();
f[0][0] = 1;
f[0][1]=1;
for (int i = 2; i <= n; i++) {
f[0][i]=f[0][i - 1] + f[1][i - 1] + f[2][i - 1];
f[1][i] = f[0][i - 2];
f[2][i] = f[1][i - 2];
}
System.out.println(f[0][n] + f[1][n] + f[2][n]);
}
}
103走路
有一条很长的数轴,一开始你在0的位置。接下来你要走n步,第i步你可以往右走ai或者bi。
问n步之后,0到m的每个位置,能不能走到
输出要求是走到最后一步之后, 可以走到的所有位置,如果最后一步走到了位置i,那么倒数第二步就需要走到i-a或者i-b,所以就考虑动态规划,用布尔数组来表示是否能走到i的位置,而每次转移就是考虑i-a或者i-b能不能走到,依次从后往前推到,这里的思路类似于走楼梯
import java.util.Scanner;
public class main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
boolean[][] st=new boolean[101][100001];
int n=sc.nextInt();
int m=sc.nextInt();
for (int i = 1; i <=n ; i++) {
int a=sc.nextInt();
int b=sc.nextInt();
for (int j = 0; j <=m ; j++) {
if(st[i-1][j]==true&&j+a<=m) st[i][j+a]=true;
if(st[i-1][j]==true&&j+b<=m) st[i][j+b]=true;
}
}
for (int i = 0; i <=m ; i++) {//输出
if(st[n][i]) System.out.print(1);
else System.out.print(0);
}
}
}
哈希表学习
知识点总结:
一般哈希表都是用来快速判断一个元素是否出现集合里
牺牲了空间换取了时间,因为我们要使用额外的数组,set或者是map来存放数据,实现快速的查找
常见的三种哈希结构
- 数组
- set (集合)
- map(映射)
map 是一个key value 的数据结构,map中,对key是有限制,对value没有限制的,因为key的存储方式使用红黑树实现的
映射 | 底层实现 | 是否有序 | 数值是否可以重复 | 能否更改数值 | 查询效率 | 增删效率 |
---|---|---|---|---|---|---|
std::map | 红黑树 | key有序 | key不可重复 | key不可修改 | O(log n) | O(log n) |
std::multimap | 红黑树 | key有序 | key可重复 | key不可修改 | O(log n) | O(log n) |
std::unordered_map | 哈希表 | key无序 | key不可重复 | key不可修改 | O(1) | O(1) |
例题1: 字母异位词
给定两个字符串 *s*
和 *t*
,编写一个函数来判断 *t*
是否是 *s*
的字母异位词。
**注意:**若 *s*
和 *t*
中每个字符出现的次数都相同,则称 *s*
和 *t*
互为字母异位词。
模板题, 因为只需要记录26个字母, 选择数组作为哈希结构, 记录s中每个字母的出现次数, 与t进行比较
class Solution {
public boolean isAnagram(String s, String t) {
int[] record=new int[26];
for(int i=0;i<s.length();i++){
record[s.charAt(i)-'a']+=1;
}
for(int i=0;i<t.length();i++){
record[t.charAt(i)-'a']-=1;
}
for(int count:record){
if(count!=0) return false;
}
return true;
}
}
例题2: 两个数字的交集
给定两个数组 nums1
和 nums2
,返回 它们的交集 。输出结果中的每个元素一定是 唯一 的
set的使用, 先将sum1的数字放入set , 在遍历2的过程中判断哈希表中是否存在该元素
class Solution {
public int[] intersection(int[] nums1, int[] nums2) {
if(nums1==null||nums1.length==0||nums2==null||nums2.length==0){
return new int[0];
}
Set<Integer> set1=new HashSet<>();
Set<Integer> resSet=new HashSet<>();
for(int i:nums1) set1.add(i);
for(int i:nums2) if(set1.contains(i)) resSet.add(i);
//return resSet.stream().mapToInt(x -> x).toArray();
int[] arr=new int[resSet.size()];
int j=0;
for(int i:resSet)
{
arr[j++]=i;
}
return arr;
}
}
例题3: 两数之和
给定一个整数数组 nums
和一个整数目标值 target
,请你在该数组中找出 和为目标值 target
的那 两个 整数,并返回它们的数组下标。
因为有两个重要元素(值, 下标), 所以选择map;
for遍历, 看map中有没有与当前元素配对的元素, 若有,加入res数组,若无, 加入map
class Solution {
public int[] twoSum(int[] nums, int target) {
int[] res=new int[2];
Map<Integer, Integer>map=new HashMap<>();
for(int i=0;i<nums.length;i++){
int temp=target-nums[i];
if(map.containsKey(temp)){
res[1]=i;
res[0]=map.get(temp);
break;
}
map.put(nums[i],i);
}
return res;
}
}
例题4: 四数相加
给你四个整数数组 nums1
、nums2
、nums3
和 nums4
,数组长度都是 n
,请你计算有多少个元组 (i, j, k, l)
能满足:
0 <= i, j, k, l < n
nums1[i] + nums2[j] + nums3[k] + nums4[l] == 0
- 首先定义 一个map,key放a和b两数之和,value 放a和b两数之和出现的次数
- 遍历A和B数组,统计两个数组元素之和,和出现的次数,放到map中
- 定义int变量count,用来统计 a+b+c+d = 0 出现的次数。
- 在遍历大C和大D数组,找到如果 0-(c+d) 在map中出现过的话,就用count把map中key对应的value也就是出现次数统计出来。(res+=map.get(0-temp))
- 最后返回统计值 count 就可以了
class Solution {
public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
Map<Integer,Integer> map=new HashMap<>();
int temp;
int res=0;
for(int i:nums1){
for(int j:nums2){
temp=i+j;
if(map.containsKey(temp)){
map.put(temp,map.get(temp)+1);
}else{
map.put(temp,1);
}
}
}
for(int i:nums3){
for(int j:nums4){
temp=i+j;
if(map.containsKey(0-temp)){
res+=map.get(0-temp);
}
}
}
return res;
}
}
例题5: 四数相加
给你两个字符串:ransomNote
和 magazine
,判断 ransomNote
能不能由 magazine
里面的字符构成。
如果可以,返回 true
;否则返回 false
。
magazine
中的每个字符只能在 ransomNote
中使用一次。
标记magazine中出现的字母, 再遍历ransomNote, 需全部包含才可以(不用管次数)
class Solution {
public boolean canConstruct(String ransomNote, String magazine) {
int[] record=new int[26];
for(char c:magazine.toCharArray()){
record[c-'a']++;
}
for(char c:ransomNote.toCharArray()){
record[c-'a']--;
}
for(int i:record){
if(i<0) return false;
}
return true;
}
}