OJ平台的树结构输入
import java.io.*;
import java.util.*;
public class Main{
public static class Node {
public int value;
public Node left;
public Node right;
public Node(int val) {
this.value = val;
}
}
//map的K是节点的值,V是这个节点在nodes节点数组中的索引
public static Node createTree(int root, int[][] childinfo, Node[] nodes, HashMap<Integer,Integer> map) {
for(int i = 0; i < nodes.length; i++) {
int left = childinfo[i][0];
int right = childinfo[i][1];
nodes[i].left = left == 0 ? null : nodes[map.get(left)];
nodes[i].right = right == 0 ? null : nodes[map.get(right)];
}
return nodes[map.get(root)];
}
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String[] s = br.readLine().split(" ");
int tree1 = Integer.parseInt(s[0]);
int root1 = Integer.parseInt(s[1]);
int[][] childinfo1 = new int[tree1][2];
Node[] nodes1 = new Node[tree1];
HashMap<Integer,Integer> map1 = new HashMap<>();
for(int i = 0; i < tree1; i++) {
s = br.readLine().split(" ");
Node node = new Node(Integer.parseInt(s[0]));
nodes1[i] = node;
childinfo1[i][0] = Integer.parseInt(s[1]);
childinfo1[i][1] = Integer.parseInt(s[2]);
map1.put(node.value,i);
}
Node first = createTree(root1,childinfo1,nodes1,map1);
s = br.readLine().split(" ");
int tree2 = Integer.parseInt(s[0]);
int root2 = Integer.parseInt(s[1]);
//System.out.println(root2);
int[][] childinfo2 = new int[tree2][2];
Node[] nodes2 = new Node[tree2];
HashMap<Integer,Integer> map2 = new HashMap<>();
for(int i = 0; i < tree2; i++) {
s = br.readLine().split(" ");
Node node = new Node(Integer.parseInt(s[0]));
//System.out.println(s[0]);
nodes2[i] = node;
childinfo2[i][0] = Integer.parseInt(s[1]);
childinfo2[i][1] = Integer.parseInt(s[2]);
map2.put(node.value,i);
}
Node second = createTree(root2,childinfo2,nodes2,map2);
System.out.print(contains(first,second)?"true":"false");
}
public static boolean contains(Node t1, Node t2){
if (t2==null){
return true;
}
if (t1==null){
return false;
}
return check(t1,t2) || contains(t1.left,t2) || contains(t1.right,t2);
}
public static boolean check(Node h,Node t2){
if (t2==null){
return true;
}
if (h==null || h.value!=t2.value){
return false;
}
return check(h.left,t2.left) && check(h.right,t2.right);
}
}
机器人的运动范围
题目描述
地上有一个 m 行和 n 列的方格。一个机器人从坐标 (0, 0) 的格子开始移动,每一次只能向左右上下四个方向移动一格,但是不能进入行坐标和列坐标的数位之和大于 k 的格子。
例如,当 k 为 18 时,机器人能够进入方格 (35,37),因为 3+5+3+7=18。但是,它不能进入方格 (35,38),因为 3+5+3+8=19。请问该机器人能够达到多少个格子?
解题思路
使用深度优先搜索(Depth First Search,DFS)方法进行求解。回溯是深度优先搜索的一种特例,它在一次搜索过程中需要设置一些本次搜索过程的局部状态,并在本次搜索结束之后清除状态。而普通的深度优先搜索并不需要使用这些局部状态,虽然还是有可能设置一些全局状态。
private static final int[][] next = {{0, -1}, {0, 1}, {-1, 0}, {1, 0}};
private int cnt = 0;
private int rows;
private int cols;
private int threshold;
private int[][] digitSum;
public int movingCount(int threshold, int rows, int cols) {
this.rows = rows;
this.cols = cols;
this.threshold = threshold;
initDigitSum();
boolean[][] marked = new boolean[rows][cols];
dfs(marked, 0, 0);
return cnt;
}
private void dfs(boolean[][] marked, int r, int c) {
if (r < 0 || r >= rows || c < 0 || c >= cols || marked[r][c])
return;
marked[r][c] = true;
if (this.digitSum[r][c] > this.threshold)
return;
cnt++;
for (int[] n : next)
dfs(marked, r + n[0], c + n[1]);
}
private void initDigitSum() {
int[] digitSumOne = new int[Math.max(rows, cols)];
for (int i = 0; i < digitSumOne.length; i++) {
int n = i;
while (n > 0) {
digitSumOne[i] += n % 10;
n /= 10;
}
}
this.digitSum = new int[rows][cols];
for (int i = 0; i < this.rows; i++)
for (int j = 0; j < this.cols; j++)
this.digitSum[i][j] = digitSumOne[i] + digitSumOne[j];
}
二叉树的输入
输入描述:
第一行输入两个整数 n 和 root,n 表示二叉树的总节点个数,root 表示二叉树的根节点。
以下 n 行每行三个整数 fa,lch,rch,表示 fa 的左儿子为 lch,右儿子为 rch。(如果 lch 为 0 则表示 fa 没有左儿子,rch同理)
输出描述:
输出两行分别表示该二叉树的先序序列化和层序序列化
示例1输入
2 1
1 2 0
2 0 0
输出
1!2!#!#!#!
1!2!#!#!#!
import java.io.*;
import java.util.*;
public class Main {
static class Node{
Node left;
Node right;
int val;
Node(int val){
this.val = val;
}
}
public static void main(String[] args) throws IOException{
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
String[] strs = reader.readLine().split(" ");
int n = Integer.valueOf(strs[0]);
Node root = new Node(Integer.valueOf(strs[1]));
HashMap<Integer,Node> map = new HashMap<>();
map.put(root.val,root);
Node left,right,parent;
//构建二叉树
for(int i=0;i<n;i++) {
String[] content = reader.readLine().split(" ");
parent = map.get(Integer.valueOf(content[0]));
int leftValue = Integer.valueOf(content[1]);
int rightValue = Integer.valueOf(content[2]);
left = leftValue == 0 ? null : new Node(leftValue);
right = rightValue == 0 ? null : new Node(rightValue);
parent.left = left;
parent.right = right;
map.put(leftValue,left);
map.put(rightValue,right);
}
/*
代码执行到这里的时候 树结构已经建立完毕,直接调用root就相当于调用了树结构。
如果输入示例建完树以后还有一行,如下
2 1
1 2 0
2 0 0
4
可以通过 String[] s=reader.readLine().split(" "); 进行获取
数据的输入问题解决以后就可以调用算法进行test了
*/
StringBuilder sb = new StringBuilder();
//前序遍历
preOrder(root,sb);
System.out.println(sb.substring(0, sb.length() - 1));
//清空StringBuilder
sb.delete(0,sb.length());
//中序遍历
inOrder(root,sb);
System.out.println(sb.substring(0, sb.length() - 1));
sb.delete(0,sb.length());
//后序遍历
postOrder(root,sb);
System.out.println(sb.substring(0, sb.length() - 1));
}
private static StringBuilder preOrder(Node treeNode, StringBuilder sb){ //前序遍历
if (treeNode == null){
return null;
}
sb.append(treeNode.val + " ");
preOrder(treeNode.left,sb);
preOrder(treeNode.right,sb);
return sb;
}
private static StringBuilder inOrder(Node treeNode, StringBuilder sb){ //中序遍历
if (treeNode == null){
return null;
}
inOrder(treeNode.left,sb);
sb.append(treeNode.val + " ");
inOrder(treeNode.right,sb);
return sb;
}
private static StringBuilder postOrder(Node treeNode, StringBuilder sb){ //后序遍历
if (treeNode == null){
return null;
}
postOrder(treeNode.left,sb);
postOrder(treeNode.right,sb);
sb.append(treeNode.val + " ");
return sb;
}
}
- 剪绳子
Leetcode
题目描述
把一根绳子剪成多段,并且使得每段的长度乘积最大。
解题思路
贪心算法或动态规划算法
尽可能多剪长度为 3 的绳子,并且不允许有长度为 1 的绳子出现。如果出现了,就从已经切好长度为 3 的绳子中拿出一段与长度为 1 的绳子重新组合,把它们切成两段长度为 2 的绳子。
证明:当 n >= 5 时,3(n - 3) - n = 2n - 9 > 0,且 2(n - 2) - n = n - 4 > 0。因此在 n >= 5 的情况下,将绳子剪成一段为 2 或者 3,得到的乘积会更大。又因为 3(n - 3) - 2(n - 2) = n - 5 >= 0,所以剪成一段长度为 3 比长度为 2 得到的乘积更大。
//贪心算法
public int integerBreak(int n) {
if (n < 2)
return 0;
if (n == 2)
return 1;
if (n == 3)
return 2;
int timesOf3 = n / 3;
if (n - timesOf3 * 3 == 1)
timesOf3--;
int timesOf2 = (n - timesOf3 * 3) / 2;
return (int) (Math.pow(3, timesOf3)) * (int) (Math.pow(2, timesOf2));
}
//动态规划
public int integerBreak(int n) {
int[] dp = new int[n + 1];
dp[1] = 1;
for (int i = 2; i <= n; i++)
for (int j = 1; j < i; j++)
dp[i] = Math.max(dp[i], Math.max(j * (i - j), dp[j] * (i - j)));
return dp[n];
}