每天重复几道题,保持手感。
看书没用,得保持手的熟练度。没事就做题,提高效率。保持实践。人的记性特别差的。
要分情况(用指针分),推理过程。分类和分步都要想。这是思维方式,每天做题训练。
积累细节的关键字,仔细观察,要具体,不要太宽的概念。这是最容易犯的错误。
具体化、实践化。积累不同的题。不然容易成书呆子,脱离实际。
输入输出语句
只有nextLine换行 其他的不换行,按行读还是按空格读,按空格最后得换行
Stringbuilder不是数组,要把容器搞清楚。
套框架+具体添加if情况(逻辑)
先把逻辑树列出来,要优化代码,不能一直if语句。选择合适的容器。
import java.util.Arrays;
import java.util.HashSet;
import java.util.Scanner;
import java.util.Set;
public class Main
{
private static String[] str;
public static void main(String args[])
{
Scanner sc=new Scanner(System.in);
int num=sc.nextInt();
sc.nextLine();
StringBuilder sb=new StringBuilder();
Set<String> set=new HashSet<>();
for(int i=0;i<num;i++){
String s=sc.nextLine();
String [] str=s.split(" ");
for(int j=0;j< str.length;j++){
if(!set.contains(str[j])){
sb.append(str[j]);
set.add(str[j]);
}
}
}
sort(sb.toString());
System.out.println();
for(int j=0;j< str.length;j++){
System.out.print(str[j]+" |");
}
}
public static void sort(String s){
str=s.split(" ");
for(int i=0;i<str.length;i++){
for(int j=i+1;j<str.length;j++){
int k=0;
String a=str[i] ;
String b=str[i] ;
while(k<str[i].length()&&k<str[j].length()){
if(a.charAt(k)<b.charAt(k)){
swap(str,i,j);
}
else if(a.charAt(k)>b.charAt(k)){
break;
}
else{
k++;
}
}
}
}
}
public static void swap(String[] s,int i, int j){
String temp=str[i];
str[i]=str[j];
str[j]=temp;
}
}
单循环+数组模拟
import java.util.*;
public class Solution {
public int maxRealValue(int m, int[] sellPrice, int[] realValue) {
// write code here
//对sellPrice 进行升序
//realValue 进行逆序
Integer[] realVal = new Integer[realValue.length];
Arrays.sort(sellPrice);
for (int i = 0; i < realValue.length; i++) {
realVal[i] = realValue[i];
}
Arrays.sort(realVal, (a,b)->b-a);
int res = 0;
for (int i = 0; i < sellPrice.length; i++) {
if (m - sellPrice[i] >= 0) {
m -= sellPrice[i];
res += realVal[i];
}
else break;
}
return res;
}
}
deque双向队列模拟
都用nextLine,要在纸上把逻辑都画好,确保能跑通。想想框架怎么跑的细节。再根据用例加条件。
import java.util.Deque;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
int num=Integer.parseInt(sc.nextLine());
int[] a=new int[num];
String s=sc.nextLine();
String [] aa=s.split(" ");
Deque<String> res=sort(aa);
int f=res.size();
for(int i=0;i<f;i++){
System.out.print(res.removeFirst()+" ");
}
}
public static Deque<String> sort(String[] a) {
int n = a.length;
Deque<String> queue = new LinkedList<>();
if(a.length<=2){
for(int i=0;i<n;i++){
queue.addFirst(a[n-i]);
}
return queue;
}
for(int i=0;i<2;i++){
queue.addFirst(a[n-i-1]);
}
for(int i=2;i<n;i++){
int g=n-i-1;
if((n-g)==3){
queue.addFirst(a[g]);
String aa=queue.removeFirst();
queue.addLast(aa);
}
else{
queue.addFirst(a[g]);
String aa=queue.removeFirst();
queue.addLast(aa);
String bb=queue.removeFirst();
queue.addLast(bb);
}
}
return queue;
}
}
回溯法:路径必须有visit,否则重复的互相调用,i+1,i-1,没完没了。
import java.awt.*;
import java.util.*;
/*
* public class Point {
* int x;
* int y;
* public Point(int x, int y) {
* this.x = x;
* this.y = y;
* }
* }
*/
public class Main {
ArrayList<Point> res=new ArrayList<Point>();
int min=Integer.MAX_VALUE;
public static void main(String[] args) {
int[][] maze=new int[4][4];
maze[0]= new int[]{0, 1, 1, 1};
maze[1]= new int[]{0, 0, 0, 1};
maze[2]= new int[]{1, 0, 8, 1};
maze[3]= new int[]{1, 0, 1, 1};
new Main().winMazeGift(maze);
}
public ArrayList<Point> winMazeGift (int[][] maze) {
int n=maze.length;int m=maze[0].length;
ArrayList<Point> t=new ArrayList<Point>();
Boolean [][] visit=new Boolean[n][m];
for(int i=0;i<n;i++) {
for (int j = 0; j < n; j++) {
visit[i][j] = false;
}
}
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
if(i==0||j==0||i==n-1||j==m-1){
if(maze[i][j]==0&&!visit[i][j]){
dfs(maze,i,j,t,visit);
}
}
}
}
return res;
}
private void dfs(int[][] maze, int i, int j, ArrayList<Point> t,Boolean[][] visit) {
if(i<0||j<0||i>=maze.length||j>=maze[0].length||maze[i][j]==1||visit[i][j])return;
Point news=new Point(i,j);
visit[i][j]=true;
t.add(news);
System.out.println(t.size());
if(maze[i][j]==8){
int s=t.size();
if(s<min){
min=s;
res=new ArrayList<>(t);
}
}
if(i-1>=0)
dfs(maze,i-1,j,t,visit);
if(i+1< maze.length)
dfs(maze,i+1,j,t,visit);
if(j-1>=0)
dfs(maze,i,j-1,t,visit);
if(j+1< maze[0].length)
dfs(maze,i,j+1,t,visit);
t.remove(news);
//必须有visit,否则重复的调用,i+1,i-1,没完没了。
visit[i][j]=false;
}
}
题的逻辑
import java.util.Arrays;
import java.util.HashSet;
import java.util.Scanner;
import java.util.Set;
public class Main2 {
private static String[] str;
public static void main(String args[])
{
Scanner sc=new Scanner(System.in);
int count=Integer.parseInt(sc.nextLine());
String s1=sc.nextLine().trim();
String s2=sc.nextLine().trim();
String res1[]=s1.split(" ");
String res2[]=s2.split(" ");
int sum1=0;
int sum2=0;
for(int i=0;i<count;i++){
int flag=score(res1[i],res2[i]);
if(flag==1){
sum1++;
}
else if(flag==-1){
sum2++;
}
}
System.out.println(sum1+" "+sum2);
}
private static int score(String s1, String s2) {
if(s1.equals(s2)){
return 0;
}
if(s1.equals("Rock")){
if(s2.equals("Scissor")){
return 1;
}
else if(s2.equals("Paper")){
return -1;
}
else
return 0;
}
if(s1.equals("Scissor")){
if(s2.equals("Paper")){
return 1;
}
else if(s2.equals("Rock")){
return -1;
}
else
return 0;
}
if(s1.equals("Paper")){
if(s2.equals("Rock")){
return 1;
}
else if(s2.equals("Scissor")){
return -1;
}
else
return 0;
}
return 0;
}
}
回溯路径:格子加缓存减少计算
import java.util.*;
public class Main3 {
// 增加缓存
public static int[][] cache;
public static void main(String[] args) {
int[][] matrix = new int[][]{{3, 4}, {1, 2 }};
System.out.println(longestIncreasingPath(matrix));
}
public static int longestIncreasingPath(int[][] matrix) {
int max=0;
cache = new int[matrix.length][matrix[0].length];
for(int i=0;i<matrix.length;i++){
for(int j=0;j<matrix[0].length;j++){
int p=dfs(matrix,i,j);
max=Math.max(p,max);
}
}
return max;
}
private static int dfs(int[][] matrix, int i, int j) {
if(i<0||j<0||i>matrix.length||j>matrix[0].length)return 0;
if(cache[i][j]!=0)return cache[i][j];
int up=1;
int down=1;
int left=1;
int right=1;
if(i-1>=0&&matrix[i-1][j]>matrix[i][j])
up+=dfs(matrix,i-1,j);
if(i+1<matrix.length&&matrix[i+1][j]>matrix[i][j])
down+=dfs(matrix,i+1,j);
if(j-1>=0&&matrix[i][j-1]>matrix[i][j])
left+=dfs(matrix,i,j-1);
if(j+1<matrix[0].length&&matrix[i][j+1]>matrix[i][j])
right+=dfs(matrix,i,j+1);
up=Math.max(up,down);
right=Math.max(left,right);
cache[i][j]=Math.max(up,right);
return cache[i][j];
}
}
1 2
3 4
dp=
1 2
2 3
回溯,组合题,存变量LinkedList list
import java.util.*;
public class Main3 {
public static boolean[] vis;
public static Set<String> set=new HashSet<>();
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
int [] nm=Arrays.stream(sc.nextLine().split(" ")).mapToInt(Integer::valueOf).toArray();
String str=sc.nextLine();
int [] ms=Arrays.stream(sc.nextLine().split(" ")).mapToInt(Integer::valueOf).toArray();
String[] substr=new String[nm[1]];
for(int i=0;i<substr.length;i++){
substr[i]=sc.nextLine();
}
int sum=Arrays.stream(ms).sum();
vis=new boolean[nm[1]];
dfs(str,ms,nm[1],substr,0,new LinkedList<String>());
System.out.println(set.size());
}
private static void dfs(String str, int[] arr, int n, String[] substr, int level, LinkedList<String> list) {
if(level==n){
set.add(list.toString());
}
for(int i=0;i<n;i++){
if(!vis[i]&&str.startsWith(substr[i])){
vis[i]=true;
list.add(substr[i]);
dfs(str,arr,n,substr,level+1,list);
vis[i]=false;
list.remove(substr[i]);
}
}
}
}
回溯加减枝
import java.util.*;
public class Main3 {
static Map<String, Integer> map = new HashMap<>();
static Set<List<String>> set = new HashSet<>();
static List<String> path = new ArrayList<>();
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
//总布料长度
int n = input.nextInt();
//小布料的个数
int m = input.nextInt();
String S = input.next();
//小布料分别长度
int[] littlelen = new int[m];
for (int i = 0; i < m; i++) {
littlelen[i] = input.nextInt();
}
//小布料分别是什么
String[] littlebl = new String[m];
for (int i = 0; i < m; i++) {
littlebl[i] = input.next();
}
//特殊情况
if (m > n) {
System.out.println(0);
}
//存小布料的Map
for (int i = 0; i < m; i++) {
map.put(littlebl[i], map.getOrDefault(littlebl[i], 0) + 1);
}
dfs(S, 0, n, m);
System.out.println(set.size());
}
static void dfs(String S, int index, int len, int target) {
if (path.size() == target) {
List<String> path2 = new ArrayList<>();
for (String s : path) {
path2.add(s);
}
set.add(path2);
return;
}
if (index >= len) {
return;
}
for (int i = index; i < len; i++) {
int j = i + 1;
while (j <= len) {
String str = S.substring(index, j);
if (map.containsKey(str) && map.get(str) != 0) {
break;
}
j++;
}
if (j > len) {
continue;
}
String str2 = S.substring(index, j);
path.add(str2);
map.put(str2, map.get(str2) - 1);
dfs(S, j, len, target);
path.remove(path.size() - 1);
map.put(str2, map.get(str2) + 1);
}
}
}
第五题(100%):贪心策略,每次碰见猫猫检查是否有玩具,有玩具的话先找出花费时间最小的玩具,再判断使用该玩具是否更省时间,没有玩具总时间加T
第五题用小根堆,100%
逻辑单循环二分,代码是从0开始的。
import java.util.Arrays;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
int n=sc.nextInt();
int x=sc.nextInt();
int y=sc.nextInt();
int[] arr=new int[n];
for (int i = 0; i < n; i++) {
arr[i]=sc.nextInt();
}
Arrays.sort(arr);
int res=Integer.MAX_VALUE;
for (int i = 0; i < n; i++) {
同下
if (i>=x-1&&i<y&&n-i>=x&&n-i<=y){
res=Math.min(res,i);
}
}
System.out.println(res==Integer.MAX_VALUE?-1:arr[res]);
}
}
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
int n=sc.nextInt();
int m1=sc.nextInt();
int m2=sc.nextInt();
int[] num=new int[n];
for(int i=0;i<n;i++){
num[i]=sc.nextInt();
}
Arrays.sort(num);
for(int i=0;i<n;i++){
//是i+1不是i,
if(i+1>=m1&&i+1<m2&&(n-i-1)>=m1&&(n-i-1)<=m2){
System.out.println(num[i]);
break;
}
}
}
}
import java.util.Arrays;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int x = scanner.nextInt();
int y = scanner.nextInt();
int[] array = new int[n];
for (int i = 0; i < n; i++) {
array[i] = scanner.nextInt();
}
Arrays.sort(array);
int l = x - 1; // 淘汰人数 l + 1
int r = n - x; // 晋级人数 n - r
while (l < r) {
if (array[l] == array[l + 1])
l++;
else if (array[r] == array[r - 1])
r--;
else if (n - r < y)
r--;
else l++;
}
System.out.println(array[r]);
}
}
l.size大坑
import java.util.Deque;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Scanner;
// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main3 {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
// 注意 hasNext 和 hasNextLine 的区别
HashSet set=new HashSet();
Deque<Character> l=new LinkedList<>();
String a = in.nextLine();
char[] c=a.toCharArray();
for (int i=0;i<c.length;i++){
if(set.contains(c[i])){
l.remove(c[i]);
}
set.add(c[i]);
l.addFirst(c[i]);
}
int ir=l.size();
for (int i=0;i<ir;i++){
char aa =l.removeFirst();
if(aa!='0')
System.out.print(aa);
}
}
}
动态规划:改变模拟思路,模拟太麻烦,用规律推理
实则题目就等于求出最长升序子字符串,但因为题目加了限制条件:每次可选择一块石头,并把它放在剩下n-1块石头的最左边或最右边。所以转变为需要我们去求出最长真升序子字符串,即相对位置与排序完的字符串对应的字符串。比如3 2 1 4 6 5,排完序后:1 2 3 4 5 6,对比两个子字符串,发现原字符串3 4 5排完序相对位置没变,所以3 4 5即为原字符串的最长真升序字符数组。找到最长真升序字符数组后,剩下有多少个其他字符就应该挪动多少次。
先读懂题逻辑题意:是n个卡片里选择3个,再想思路算法。
import java.awt.*;
import java.util.*;
import java.util.List;
public class Main {
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
int n =sc.nextInt();
sc.nextLine();
Collection<String> l=new ArrayList<>();
for(int i=0;i<n;i++){
l.add(sc.next());
}
Collections.sort((List)l,new Comparator<String>(){
@Override
public int compare(String o,String i) {
int r=-Integer.valueOf(o+i)+Integer.valueOf(i+o);
return r;
}
});
String res="";
String last="";
int max=0;
for(int i=0;i<l.size();i++){
if(i<2)
res+=((List) l).get(i);
else{
int t=Integer.parseInt((String) ((List) l).get(i));
if(max<t){
max=t;
}
}
}
res+=String.valueOf(max);
System.out.println(res);
}
}
回溯题识别:每次多个选择进行模拟,找最小。没办法找到规律的情况下。
import java.util.*;
public class Main2 {
public static void main(String args[])
{
Scanner sc=new Scanner(System.in);
int n =sc.nextInt();
Collection<String> l=new ArrayList<>();
for(int i=0;i<n;i++){
Long a =sc.nextLong();
Long b =sc.nextLong();
if(a>b){
Long t=a;
a=b;
b=t;
}
int [] min=new int[1];
min[0]=1000000;
dfs(a,b,0,min);
if(min[0]==1000000)min[0]=-1;
System.out.println(min[0]);
}
}
private static void dfs(Long a, Long b,int count,int[] min) {
if(a==b){
if(count<min[0])
min[0]=count;
}
else if(a<b) {
for (int i = 2; i <= 8; i *= 2) {
dfs(a * i, b, count + 1, min);
}
}
}
}
类转化,List模拟。需要自己输入例子测试
import java.util.*;
class Main{
public static void main(String [] args){
Scanner sc=new Scanner(System.in);
String s=sc.next();
String c=sc.next();
Deque<String> dq=new LinkedList();
for(int i=0;i<s.length();i++){
dq.addLast(String.valueOf(s.charAt(i)));
}
single(dq,c);
}
public static void single(Deque<String> dp,String c){
while(dp.peekFirst().equals(c))dp.removeFirst();
while(dp.peekLast().equals(c))dp.removeLast();
int n=dp.size();
for(int i=0;i<n;i++){
System.out.print(dp.removeFirst());
}
}
}
import java.util.*;
class Main{
public static void main(String [] args){
Scanner sc=new Scanner(System.in);
List<Integer> l=new ArrayList();
while(sc.hasNext()){
l.add(sc.nextInt());
}
single(l);
}
public static void single(List<Integer> nums){
Set<Integer> set=new HashSet<>();
for(int i=0;i<nums.size();i++){
if(set.contains(nums.get(i)))
set.remove(nums.get(i));
else
set.add(nums.get(i));
}
Object [] r=new Object[set.size()];
r=set.toArray();
Arrays.sort(r);
for(int i=0;i<r.length;i++){
//obj转化成string
System.out.print(String.valueOf(r[i])+" ");
}
}
}
树前序遍历+queue模拟
class Solution {
/* Write Code Here */
public Node Convert(Node pRootOfTree) {
Queue<Node> q =new LinkedList<>();
dfs(pRootOfTree,q);
if(q.isEmpty())return pRootOfTree;
Node node =q.poll();
Node pre=node;
pre.left=null;
Node cur=null;
while(!q.isEmpty()){
cur=q.poll();
pre.right=cur;
cur.left=pre;
pre=cur;
}
pre.right=null;
return node;
}
private void dfs(Node pRootOfTree, Queue<Node> queue) {
if(pRootOfTree==null)return ;
dfs(pRootOfTree.left,queue);
queue.add(pRootOfTree);
dfs(pRootOfTree.right,queue);
}
}
ListNode链表模拟
class Solution {
/* Write Code Here */
public ListNode<Integer> reverseBetween(ListNode<Integer> head, int left, int right) {
if(head==null||head.next==null)return head;
else {
//哨兵节点
ListNode newnode=new ListNode<>(-1);
newnode.next=head;
ListNode pre=newnode;
for(int i=0;i<left-1;i++){
pre=pre.next;
}
ListNode hou=pre;
for(int i=0;i<(right-left+1);i++){
hou=hou.next;
}
ListNode qian=pre.next;
ListNode houhou=hou.next;
//断开后反转
pre.next=null;
hou.next=null;
reverse(qian);
//连接,每个Node都是对象,对象不变,连接
pre.next=hou;
qian.next=houhou;
return newnode.next;
}
}
private void reverse(ListNode qian) {
ListNode pre=null;
ListNode cur=qian;
while(cur!=null){
ListNode next=cur.next;
cur.next=pre;
pre=cur;
cur=next;
}
}
}
dp一维+字符串模拟
import java.io.*;
import java.util.*;
import java.text.*;
import java.math.*;
import java.util.regex.*;
public class Main {
public static void main(String[] args){
Scanner sc=new Scanner(System.in);
String bs=sc.nextLine();
int n=Integer.valueOf(bs);
int []res=new int[n];
for(int i=0;i<n;i++){
String kk=sc.nextLine();
String[] ss=kk.split(" ");
int l=Integer.valueOf(ss[0]);
int t=Integer.valueOf(ss[1]);
boolean p=sc.hasNext();
String s=sc.nextLine();
String ssss="";
if(s=="")
ssss="s";
find(s,l,t);
}
}
private static void find(String s, int l, int t) {
int[] dp=new int [l];
for(int i=t;i<l;i++){
char c=s.charAt(i);
if(c!=s.charAt(i-t)){
dp[i]=dp[i-1]+1;
}
else
dp[i]=dp[i-1];
}
System.out.println(dp[l-1]);
}
}
数组模拟+特殊条件
import java.io.*;
import java.util.*;
import java.text.*;
import java.math.*;
import java.util.regex.*;
public class Main2 {
public static void main(String[] args){
Scanner sc=new Scanner(System.in);
int n=sc.nextInt();
sc.nextLine();
int res=Integer.MIN_VALUE;
for(int i=0;i<n;i++){
String a=sc.nextLine();
int[] num=new int[26];
for(int j=0;j<a.length();j++){
num[a.charAt(j)-'a']+=1;
}
int max=Integer.MIN_VALUE;int min=Integer.MAX_VALUE;
for(int j=0;j<num.length;j++){
if(num[j]>=max)max=num[j];
//特殊条件
if(num[j]<=min&&num[j]!=0)min=num[j];
}
int d=max-min;
if(d>res)res=d;
}
System.out.println(res);
}
}
数组模拟
import java.io.*;
import java.util.*;
import java.text.*;
import java.math.*;
import java.util.regex.*;
public class Main3 {
public static void main(String[] args){
Scanner sc=new Scanner(System.in);
int n=sc.nextInt();
int m=sc.nextInt();
int []l=new int [n];
int []r=new int [n];
int max=0;
for(int i=0;i<n;i++){
l[i]=sc.nextInt();
if(l[i]>max)max=l[i];
r[i]=sc.nextInt();
if(r[i]>max)max=r[i];
}
int []count=new int [max];
for(int i=0;i<n;i++){
for(int j=l[i];j<r[i];j++)
count[j]+=1;
}
int res=0;
for(int i=0;i<max;i++){
if(count[i]>=m)
res++;
}
System.out.println(res);
}
}
hashset模拟
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Scanner;
import java.util.Set;
// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main4 {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
// 注意 hasNext 和 hasNextLine 的区别
Set<String> s=new HashSet<>();
s.add(",");
s.add(" ");
s.add(" ");
s.add(",");
LinkedList<String> l=new LinkedList<>();
String as=in.nextLine();
String[] ss=as.split("");
for(int i=0;i<ss.length;i++){
String a = ss[i];
char[] cc=a.toCharArray();
int n=cc[0]-'0';
if(!s.contains(a)&&n>=0&&n<=9||a.equals("[")||a.equals("]")){
s.add(a);
l.add(a);
}
}
System.out.print(l.get(0));
for(int i=1;i<l.size()-2;i++){
System.out.print(l.get(i)+",");
}
System.out.print(l.get(l.size()-2));
System.out.print(l.get(l.size()-1));
}
}
list模拟,暴力穷举法
import java.util.*;
// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main5 {
public static void main(String[] args) {
int i=0;int j=0;int m=0;int c=0;
ArrayList<Integer> t=new ArrayList<>();
for( i=1;i<=4;i++){
for( j=1;j<=4;i++){
for( m=1;m<=4;i++){
if(i!=j&&j!=m&&m!=i){
c=c+1;
t.add(i*100+j*10+m);
}
}
}
}
System.out.println("总数:"+c);
System.out.println("无重复组合:"+t.toString());
}
}
递归
import java.util.*;
public class Main6 {
public int numberOfTree (int n) {
if(n<2)return n;
return dfs(2*n,n)/(1+n);
}
private int dfs(int i, int j) {
if(i==j||j==0)return 1;
else
return dfs(i-1,j)+dfs(i-1,j-1);
}
}