目录
01.二维数组中的查找
02.替换空格
03.从尾到头打印链表
04.根据前序和中序重建二叉树
05.用两个栈实现队列
06.旋转数组的最小数字
07.斐波那契数列
08.跳台阶
09.升级版跳台阶
10.矩形覆盖
11.二进制中1的个数
12.数值的整数次方
13.调整数组顺序使奇数位于偶数前面
14.链表中倒数第k个节点
15.反转链表
16.合并两个排序的链表
17.树的子结构
18.二叉树的镜像
19.顺时针打印矩阵
20.包含min函数的栈
21.栈的压入、弹出序列
22.从上至下逐层打印二叉树
23.二叉搜索树的后序遍历序列
24.二叉树中和为某一值的路径
25.复杂链表的复制
26.二叉搜索树与双向链表
27.字符串的排列
28.数组中出现次数超过一半的数字
29.最小的k个数
30.连续子数组的最大和
31.整数中1出现的次数(从1到n整数中1出现的次数)
32.把数组排成最小的数
33.丑数
34.第一个只出现一次的字符
35.数组中的逆序对
36.两个链表的第一个公共节点
37.数字在排序数组中出现的次数
38.二叉树的深度
39.平衡二叉树
40.数组中只出现一次的数字
41.和为S的连续正数序列
42.和为S的两个数字
43.左旋转字符串
44.旋转单词顺序列
45.扑克牌顺子
46.孩子们的游戏(圆圈中最后剩下的数)
47.求1+2+3+...+n
48.不用加减乘除做加法
49.把字符串转换成整数
50.数组中重复的数字
51.构建乘积数组
52.正则表达式匹配
53.表示数值的字符串
54.字符流中第一个不重复的字符
55.链表中环的入口节点
56.删除链表中重复的节点
57.二叉树的下一个节点
58.对称的二叉树
59.按之字形打印二叉树
60.把二叉树打印成多行
61.序列化二叉树
62.二叉搜索树的第k个节点
63.数据流的中位数
64.滑动窗口的最大值
65.矩阵中的路径
66.机器人的运动范围
END
题目描述
在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
public class Solution {
public boolean Find(int target, int [][] array) {
//从右上角到左下角遍历
int row = 0, col = array[0].length - 1;
while(row < array.length && col >= 0) {
if(target == array[row][col])
return true;
//target小于当前值,说明下方和右方整个块全部作废,因此左移1位
else if(target < array[row][col])
col--;
else
row++;
}
return false;
}
}
题目描述
请实现一个函数,将一个字符串中的每个空格替换成“%20”。例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。
public class Solution {
public String replaceSpace(StringBuffer str) {
String s = str.toString();
String res = "";
for(int i = 0; i < s.length(); i++) {
if(s.charAt(i) == ' ')
res += "%20";
else
res += s.charAt(i);
}
return res;
}
}
题目描述
输入一个链表,按链表值从尾到头的顺序返回一个ArrayList。
import java.util.ArrayList;
public class Solution {
public ArrayList printListFromTailToHead(ListNode listNode) {
ArrayList arrayList = new ArrayList();
ListNode head = reverseList(listNode);
while(head != null) {
arrayList.add(head.val);
head = head.next;
}
return arrayList;
}
//链表转置函数
public static ListNode reverseList(ListNode listNode) {
ListNode tail = null;
while(listNode != null){
ListNode p = listNode.next; //储存next
listNode.next = tail;
tail = listNode; //更新tail
listNode = p;
}
return tail;
}
}
题目描述
输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。
public class Solution {
public TreeNode reConstructBinaryTree(int [] pre,int [] in) {
return reConstructBinaryTree(pre, 0, pre.length - 1, in, 0, in.length - 1);
}
//用下标获取每个子树的前序和中序序列
public TreeNode reConstructBinaryTree(int [] pre, int preStart, int preEnd,
int [] in, int inStart, int inEnd) {
if(preStart > preEnd || inStart > inEnd) //序列为空,返回null
return null;
TreeNode res = new TreeNode(pre[preStart]); //前序第1个值是根节点
if(preStart == preEnd) //只有一个节点
return res;
int leftCount = 0; //左子树的大小
for(int i = inStart; in[i] != pre[preStart]; i++)
leftCount++;
res.left = reConstructBinaryTree(pre, preStart + 1, preStart + leftCount,
in, inStart, inStart + leftCount - 1);
res.right = reConstructBinaryTree(pre, preStart + leftCount + 1, preEnd,
in, inStart + leftCount + 1, inEnd);
return res;
}
}
题目描述
用两个栈来实现一个队列,完成队列的Push和Pop操作。 队列中的元素为int类型。
import java.util.Stack;
public class Solution {
Stack stack1 = new Stack();
Stack stack2 = new Stack();
public void push(int node) {
stack1.push(node);
}
public int pop() {
if(stack2.isEmpty()) { //stack2为空时,stack1中要全部移入stack2保证顺序
while(!stack1.isEmpty())
stack2.push(stack1.pop());
}
return stack2.pop();
}
}
题目描述
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。 输入一个非减排序的数组的一个旋转,输出旋转数组的最小元素。 例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。 NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。
public class Solution {
public int minNumberInRotateArray(int [] array) {
if(array.length == 0)
return 0;
int start = 0, end = array.length - 1;
//二分查找
while(start < end) {
int mid = (start + end) / 2;
if(array[mid] < array[start]) //最小值在左半边(要包括mid)
end = mid;
else if(array[mid] > array[end]) //最小值在右半边(不包括mid)
start = mid + 1;
else //即 array[start] <= array[mid] <= array[end]
return array[start];
}
return array[start];
}
}
题目描述
大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项(从0开始,第0项为0)。
n<=39
public class Solution {
public int Fibonacci(int n) {
int a = 0, b = 1;
for(int i = 0; i < n / 2; i++) {
a += b;
b += a;
}
return n % 2 == 0 ? a : b;
}
}
题目描述
一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果)。
public class Solution {
public int JumpFloor(int target) {
//还是斐波那契数列
int a = 1, b = 2;
for(int i = 0; i < (target - 1) / 2; i++) {
a += b;
b += a;
}
return target % 2 == 1 ? a : b;
}
}
题目描述
一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。
public class Solution {
public int JumpFloorII(int target) {
if(target <= 2)
return target;
//用list保存target从1到target每个值的跳法数
//根据最后1步跳的距离区分,是1到target-1时,跳法数分别对应list[target-1]到list[1]
//最后再加1(就是最后1步跳整个target长)
//即,list[i]=1+list[i-1]+list[i-2]+...+list[0],不知是否有通项公式,暂且不管
int[] list = new int[target];
list[0] = 1;
list[1] = 2;
for(int i = 2; i < target; i++) {
int sum = 0;
for(int j = 0; j < i; j++)
sum += list[j];
list[i] = sum + 1;
}
return list[target - 1];
}
}
题目描述
我们可以用2*1的小矩形横着或者竖着去覆盖更大的矩形。请问用n个2*1的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法?
public class Solution {
public int RectCover(int target) {
//又是斐波那契数列
if(target == 0)
return 0;
int a = 1, b = 2;
for(int i = 0; i < (target - 1) / 2; i++) {
a += b;
b += a;
}
return target % 2 == 1 ? a : b;
}
}
题目描述
输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。
public class Solution {
public int NumberOf1(int n) {
int count = 0;
while(n != 0){
count++;
//n&(n-1)可以消掉最右边的一个1
n = n & (n - 1);
}
return count;
}
}
题目描述
给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。
public class Solution {
public double Power(double base, int exponent) {
if(exponent == 0)
return 1.0;
boolean isNegExponent = false;
//注意判断负指数
if(exponent < 0) {
isNegExponent = true;
exponent = -exponent;
}
//直接递归求根号值就ok
double sqrtRes = Power(base, exponent / 2);
double res = 1.0;
if(exponent % 2 == 0)
res = sqrtRes * sqrtRes;
else
res = sqrtRes * sqrtRes * base;
if(isNegExponent)
return 1 / res;
else
return res;
}
}
题目描述
输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。
public class Solution {
public void reOrderArray(int [] array) {
//和插入排序相同
int insertPos = 0; //插入位置
boolean allOdd = true;
for(int i = 0; i < array.length; i++) {
if(allOdd && array[i] % 2 == 0) { //发现第一个偶数,即为插入位置
allOdd = false;
insertPos = i;
}
if(!allOdd && array[i] % 2 != 0) { //当前是奇数且前面不全为奇,插入
int temp = array[i];
int j = i - 1;
for(; j >= insertPos; j--)
array[j + 1] = array[j];
array[j + 1] = temp;
insertPos++; //因为全部后移了1位,插入位置+1
}
}
}
}
题目描述
输入一个链表,输出该链表中倒数第k个结点。
public class Solution {
public ListNode FindKthToTail(ListNode head,int k) {
if(k <= 0)
return null;
int length = 0;
ListNode l1 = head, l2 = head;
for(; l1 != null; l1 = l1.next) //先获取链表长度
length++;
if(length < k) //k值过大
return null;
l1 = head;
for(int i = 0; i < k; i++) //l2先移动k次,以便与l1的距离为k
l2 = l2.next;
while(l2 != null) {
l1 = l1.next;
l2 = l2.next;
}
return l1;
}
}
题目描述
输入一个链表,反转链表后,输出新链表的表头。
public class Solution {
//链表转置函数
public static ListNode ReverseList(ListNode head) {
ListNode tail = null;
while(head != null){
ListNode p = head.next; //储存next
head.next = tail;
tail = head; //更新tail
head = p;
}
return tail;
}
}
题目描述
输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。
public class Solution {
public ListNode Merge(ListNode list1,ListNode list2) {
if(list1 == null)
return list2;
if(list2 == null)
return list1;
if(list1.val <= list2.val) { //递归即可
list1.next = Merge(list1.next, list2);
return list1;
}
else {
list2.next = Merge(list2.next, list1);
return list2;
}
}
}
题目描述
输入两棵二叉树A,B,判断B是不是A的子结构。(ps:我们约定空树不是任意一个树的子结构)
public class Solution {
public boolean HasSubtree(TreeNode root1,TreeNode root2) {
//前序遍历
//这道题的意思是值相同,不是指同一节点,且可以只是中间部分的子结构
if(root2 == null || root1 == null) //由题意都不为null才行
return false;
if(HasSubtreeFromRoot(root1, root2)) //先判断根节点
return true;
else //递归左右
return HasSubtree(root1.left, root2) || HasSubtree(root1.right, root2);
}
public boolean HasSubtreeFromRoot(TreeNode root1,TreeNode root2) {
//root1可能包含root2,从根节点开始比较,只要root2能遍历完即可
//以下保证输入root2非空
if(root1 == null)
return false;
else if(root1.val != root2.val)
return false;
boolean res = true;
if(root2.left != null) //非空就要递归判断
res = res && HasSubtreeFromRoot(root1.left, root2.left);
if(root2.right != null)
res = res && HasSubtreeFromRoot(root1.right, root2.right);
return res;
}
}
题目描述
操作给定的二叉树,将其变换为源二叉树的镜像。
输入描述:
二叉树的镜像定义:源二叉树
8
/ \
6 10
/ \ / \
5 7 9 11
镜像二叉树
8
/ \
10 6
/ \ / \
11 9 7 5
public class Solution {
public void Mirror(TreeNode root) {
if(root != null) {
//先交换左右子树,再分别置镜像
TreeNode temp = root.left;
root.left = root.right;
root.right = temp;
Mirror(root.left);
Mirror(root.right);
}
}
}
题目描述
输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下4 X 4矩阵: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 则依次打印出数字1,2,3,4,8,12,16,15,14,13,9,5,6,7,11,10.
import java.util.ArrayList;
public class Solution {
public ArrayList printMatrix(int [][] matrix) {
ArrayList res = new ArrayList();
if(matrix.length == 0)
return res;
int step = 0; //第几圈
int i = step, j = step;
//总共的圈数,由matrix的长和宽中较小的那个决定
int totalLoops = (Math.min(matrix.length, matrix[0].length) + 1) / 2;
while(step < totalLoops) {
while(j < matrix[0].length - step) //向右到最右,否则一条线构不成圈时会漏掉
res.add(matrix[i][j++]);
j--; //第一个方向一定会执行,j回位
i++; //行数下移1
while(i < matrix.length - step) //向下,同样要到最下
res.add(matrix[i++][j]);
//前两个方向结束就可以判断退出
if(i == step + 1 || j == step) //分别是一行和一列的情况,退出
break;
i--; //i回位
j--; //j左移1
while(j > step) //向左
res.add(matrix[i][j--]);
while(i > step) //向上
res.add(matrix[i--][j]);
step++;
i = step;
j = step;
}
return res;
}
}
题目描述
定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的min函数(时间复杂度应为O(1))。
import java.util.Stack;
public class Solution {
long min;
Stack stack = new Stack();
public void push(int node) {
if(stack.isEmpty()) {
stack.push((long)node);
min = (long)node;
}
else {
stack.push((long)node - min); //入栈的是node减去(旧的)min
if((long)node < min) //更新min
min = (long)(node);
}
}
public void pop() {
if(stack.isEmpty())
return;
long pop = stack.pop();
if(pop < 0) //出栈的是更新了min的node,min要还原
min = min - pop; //右边min是node真实值,而pop是node真实值减去(旧的)min
}
public int top() {
long top = stack.peek();
if(top >= 0)
return (int)(top + min);
else //top小于0时,node减去的是旧的min,当前min是node真实值
return (int)min;
}
public int min() {
return (int)min;
}
}
题目描述
输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。(注意:这两个序列的长度是相等的)
import java.util.ArrayList;
import java.util.Stack;
public class Solution {
public boolean IsPopOrder(int [] pushA,int [] popA) {
if(pushA.length != popA.length)
return false;
Stack stack = new Stack();
int i = 0;
//对每个出栈序列元素执行检测,匹配上则pop(),否则返回false
for(int j = 0; j < popA.length; j++) {
//一直入栈直到匹配成功
while(stack.empty() || stack.peek() != popA[j]) {
if(i < pushA.length) //i合法,继续入栈
stack.push(pushA[i++]);
else //i越界,匹配失败
return false;
}
stack.pop(); //匹配成功后出栈
}
return true;
}
}
题目描述
从上往下打印出二叉树的每个节点,同层节点从左至右打印。
public class Solution {
public ArrayList PrintFromTopToBottom(TreeNode root) {
//层次遍历即可
ArrayList res = new ArrayList();
if(root == null)
return res;
Queue queue = new LinkedList();
queue.offer(root);
while(!queue.isEmpty()) {
TreeNode cur = queue.poll();
res.add(cur.val);
if(cur.left != null)
queue.offer(cur.left);
if(cur.right != null)
queue.offer(cur.right);
}
return res;
}
}
题目描述
输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。
public class Solution {
public boolean VerifySquenceOfBST(int [] sequence) {
//后序遍历是左,右,中
//起始就是空数组时,不算是搜索树,返回false
if(sequence.length == 0)
return false;
return VerifySquenceOfBST(sequence, 0, sequence.length - 1);
}
public boolean VerifySquenceOfBST(int [] sequence, int start, int end) {
//对于子树,start > end视作空子树,返回true
if(start >= end)
return true;
int i = start;
int leftEnd = start;
//左子树全部比根节点小
while(sequence[i] < sequence[end])
i++;
leftEnd = i - 1;
//右子树全部比根节点大
while(sequence[i] > sequence[end])
i++;
//到达根节点
if(i == end)
return VerifySquenceOfBST(sequence, start, leftEnd) && VerifySquenceOfBST(sequence, leftEnd + 1, end - 1);
//没有到达,返回false
else
return false;
}
}
题目描述
输入一颗二叉树的跟节点和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。(注意: 在返回值的list中,数组长度大的数组靠前)
public class Solution {
public ArrayList> FindPath(TreeNode root,int target) {
ArrayList> res = new ArrayList>();
ArrayList list = new ArrayList();
preOrder(root, target, res, list);
return res;
}
//前序遍历
public void preOrder(TreeNode cur, int target, ArrayList> res, ArrayList list) {
if(cur != null) {
list.add(cur.val); //加入list
if(cur.left == null && cur.right == null && cur.val == target) //满足条件的叶节点
res.add(new ArrayList(list)); //要先复制list再加入res才对
else {
preOrder(cur.left, target - cur.val, res, list);
preOrder(cur.right, target - cur.val, res, list);
}
list.remove(list.size() - 1); //回退时需要移除最后一个元素
}
}
}
题目描述
输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点),返回结果为复制后复杂链表的head。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空)
/*
public class RandomListNode {
int label;
RandomListNode next = null;
RandomListNode random = null;
RandomListNode(int label) {
this.label = label;
}
}
*/
import java.util.HashMap;
public class Solution {
public RandomListNode Clone(RandomListNode pHead) {
//题的意思应该是深拷贝,random不能指向原链表的节点才对
//借助额外空间,用HashMap映射原节点和新节点
if(pHead == null)
return null;
HashMap map = new HashMap();
RandomListNode res = new RandomListNode(pHead.label);
map.put(pHead, res);
//先复制值得到新链表,注意l2比l1慢1个节点
for(RandomListNode l1 = pHead.next, l2 = res; l1 != null; l1 = l1.next) {
l2.next = new RandomListNode(l1.label);
l2 = l2.next;
map.put(l1, l2);
}
//再完善random指针,l1和l2同步
for(RandomListNode l1 = pHead, l2 = res; l1 != null; l1 = l1.next, l2 = l2.next)
l2.random = map.get(l1.random);
return res;
}
}
题目描述
输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。
public class Solution {
//全局变量保存链表头和尾
TreeNode head = null;
TreeNode tail = null;
public TreeNode Convert(TreeNode pRootOfTree) {
inOrder(pRootOfTree);
return head;
}
//中序遍历
public void inOrder(TreeNode root) {
if(root != null) {
inOrder(root.left);
if(head == null) {
head = root;
tail = root;
}
else {
tail.right = root;
root.left = tail;
tail = root;
}
inOrder(root.right);
}
}
}
题目描述
输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。
输入描述:
输入一个字符串,长度不超过9(可能有字符重复),字符只包括大小写字母。
import java.util.ArrayList;
public class Solution {
public ArrayList Permutation(String str) {
ArrayList res = new ArrayList();
if(str.length() == 0)
return res;
permute(str.toCharArray(), 0, res); //生成res
//转换成String[]以便排序
String[] array = (String[])res.toArray(new String[res.size()]);
quickSort(array, 0, array.length - 1);
res = new ArrayList(Arrays.asList(array));
return res;
}
public void permute(char[] ch, int i, ArrayList list) {
if(i == ch.length - 1) { //递归出口
String cur = new String(ch);
if(!list.contains(cur)) //如果没有重复就存入当前字符串
list.add(cur);
}
else {
for(int j = i; j < ch.length; j++) { //逐个交换字母,递归,再换回
swap(ch, i, j);
permute(ch, i + 1, list);
swap(ch, i, j);
}
}
}
public void swap(char[] ch, int i, int j) { //交换两个字母顺序
char temp = ch[i];
ch[i] = ch[j];
ch[j] = temp;
}
//快排String[]
public void quickSort(String[] array, int start, int end) {
if(array.length == 0 || start >= end)
return;
String pivot = array[start];
int i = start, j = end;
while(i < j) {
while(i < j && array[j].compareTo(pivot) >= 0)
j--;
if (i < j)
array[i++] = array[j];
while(i < j && array[i].compareTo(pivot) < 0)
i++;
if (i < j)
array[j--] = array[i];
}
array[i] = pivot;
quickSort(array, start, i - 1);
quickSort(array, i + 1, end);
}
}
题目描述
数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。
public class Solution {
public int MoreThanHalfNum_Solution(int [] array) {
//这道题要利用数组的特殊性质,不需要HashMap
if(array.length == 0)
return 0;
int res = array[0];
int count = 1;
//经过第一次循环假如有超过一半的元素一定会留下来
for(int i = 1; i < array.length; i++) {
if(count == 0) { //count为0,更新res
res = array[i];
count = 1;
}
else if(array[i] == res)
count++;
else
count--;
}
//第二次循环验证留下来的是否是超过一半次的元素
count = 0;
for(int i = 0; i < array.length; i++) {
if(array[i] == res)
count++;
if(count > array.length / 2)
return res;
}
return 0;
}
}
题目描述
输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,。
import java.util.ArrayList;
public class Solution {
public ArrayList GetLeastNumbers_Solution(int [] input, int k) {
//选择排序k次
ArrayList res = new ArrayList();
if(k <= 0 || k > input.length)
return res;
for(int i = 0; i < k; i++) {
int min = input[i], minIndex = i;
for(int j = i + 1; j < input.length; j++) {
if(input[j] < min) { //更新最小值及其位置
min = input[j];
minIndex = j;
}
}
int temp = input[i]; //swap
input[i] = min;
input[minIndex] = temp;
}
for(int i = 0; i < k; i++)
res.add(input[i]);
return res;
}
}
题目描述
HZ偶尔会拿些专业问题来忽悠那些非计算机专业的同学。今天测试组开完会后,他又发话了:在古老的一维模式识别中,常常需要计算连续子向量的最大和,当向量全为正数的时候,问题很好解决。但是,如果向量中包含负数,是否应该包含某个负数,并期望旁边的正数会弥补它呢?例如:{6,-3,-2,7,-15,1,2,2},连续子向量的最大和为8(从第0个开始,到第3个为止)。给一个数组,返回它的最大连续子序列的和,你会不会被他忽悠住?(子向量的长度至少是1)
public class Solution {
public int FindGreatestSumOfSubArray(int[] array) {
int curSum = array[0]; //curSum的定义是包含当位的值
int maxSum = curSum;
for(int i = 1; i < array.length; i++){
if(curSum <= 0) //旧的和非正数,则抛弃
curSum = array[i];
else
curSum = curSum + array[i];
maxSum = Math.max(maxSum, curSum); //更新maxSum
}
return maxSum;
}
}
题目描述
求出1~13的整数中1出现的次数,并算出100~1300的整数中1出现的次数?为此他特别数了一下1~13中包含1的数字有1、10、11、12、13因此共出现6次,但是对于后面问题他就没辙了。ACMer希望你们帮帮他,并把问题更加普遍化,可以很快的求出任意非负整数区间中1出现的次数(从1 到 n 中1出现的次数)。
public class Solution {
public int NumberOf1Between1AndN_Solution(int n) {
//计算逐个位的1的次数并求和
int count = 0;
int weight = 1;
int r = 0; //余数,用来计算当位是1时这个1带来的个数
while(weight <= n) {
r = n % weight;
if((n / weight) % 10 > 1) //当位大于1时增加weight个(如百位含100~199共100个1)
count += weight;
else if((n / weight) % 10 == 1) //当位是1时增加r+1个(如百位含100~109共10个1)
count += r + 1;
count += (n / weight / 10) * weight; //高位带来的当位1的个数,
//如00100到23199,除去额外的199,百位增加共23*100个1
//千万不能化简算式,否则最高位时结果不同!
weight *= 10;
}
return count;
}
}
题目描述
输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323。
public class Solution {
public String PrintMinNumber(int [] numbers) {
//普通排序即可,如果交换位置后拼成的数更小,就交换
for(int i = 0; i < numbers.length - 1; i++){
for(int j = i + 1; j < numbers.length; j++){
int a = Integer.valueOf(numbers[i]+""+numbers[j]);
int b = Integer.valueOf(numbers[j]+""+numbers[i]);
if(a > b){
int temp = numbers[i];
numbers[i] = numbers[j];
numbers[j] = temp;
}
}
}
String str = "";
for(int i = 0; i < numbers.length; i++)
str += numbers[i];
return str;
}
}
题目描述
把只包含质因子2、3和5的数称作丑数(Ugly Number)。例如6、8都是丑数,但14不是,因为它包含质因子7。 习惯上我们把1当做是第一个丑数。求按从小到大的顺序的第N个丑数。
public class Solution {
/*丑数可以分为三个序列
(1) 1×2, 2×2, 3×2, 4×2, 5×2, …
(2) 1×3, 2×3, 3×3, 4×3, 5×3, …
(3) 1×5, 2×5, 3×5, 4×5, 5×5, …
每个序列都是丑数序列本身 * 2, 3, 5,每次从这三个序列选最小就可以获取丑数序列;
之后更新(包括重复值也要更新才行)*/
public int GetUglyNumber_Solution(int n) {
if(n == 0)
return 0;
int[] ugly = new int[n];
ugly[0] = 1;
int index2 = 0, index3 = 0, index5 = 0;
int factor2 = 2, factor3 = 3, factor5 = 5;
for(int i = 1; i < n; i++) {
int min = Math.min(Math.min(factor2, factor3), factor5); //选最小
ugly[i] = min;
if(factor2 == min) //因为可能有重复值,一定要3个都判断并更新,不可以用else
factor2 = 2 * ugly[++index2];
if(factor3 == min)
factor3 = 3 * ugly[++index3];
if(factor5 == min)
factor5 = 5 * ugly[++index5];
}
return ugly[n - 1];
}
}
题目描述
在一个字符串(0<=字符串长度<=10000,全部由字母组成)中找到第一个只出现一次的字符,并返回它的位置, 如果没有则返回 -1(需要区分大小写).
import java.util.HashMap;
public class Solution {
public int FirstNotRepeatingChar(String str) {
//直接上HashMap计数即可
HashMap map = new HashMap();
int res = -1;
for(int i = 0; i < str.length(); i++)
map.put(str.charAt(i), map.getOrDefault(str.charAt(i), 0) + 1);
for(int i = 0; i < str.length(); i++)
if(map.get(str.charAt(i)) == 1) {
res = i;
break;
}
return res;
}
}
题目描述
在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数P。并将P对1000000007取模的结果输出。 即输出P%1000000007
输入描述:
题目保证输入的数组中没有的相同的数字
数据范围:
对于%50的数据,size<=10^4
对于%75的数据,size<=10^5
对于%100的数据,size<=2*10^5
public class Solution {
public int InversePairs(int [] array) {
//归并排序并且统计逆序数
long[] count = new long[1];
mergeSort(array, 0, array.length - 1, count);
return (int)count[0];
}
//归并排序
public void mergeSort(int[] array, int start, int end, long[] count) {
if(start >= end)
return;
int mid = start + (end - start) / 2; //预防int溢出的写法
mergeSort(array, start, mid, count);
mergeSort(array, mid + 1, end, count);
merge(array, start, mid, end, count);
}
public void merge(int[] array, int start, int mid, int end, long[] count) {
//对start到mid,以及mid+1到end两部分进行合并
int[] temp = new int[end - start + 1];
int i = start, j = mid + 1, k = 0;
while(i <= mid && j <= end) {
if(array[i] > array[j]) { //出现逆序,更新count
temp[k++] = array[j++];
count[0] += mid - i + 1; //右侧array[j]左移越过的左侧个数即增加的逆序数
count[0] %= 1000000007; //预防数值过大溢出
}
else
temp[k++] = array[i++];
}
while(i <= mid)
temp[k++] = array[i++];
while(j <= end)
temp[k++] = array[j++];
for (k = 0; k < temp.length; k++) //将合并后数组移回原数组
array[start + k] = temp[k];
}
}
题目描述
输入两个链表,找出它们的第一个公共结点。
public class Solution {
public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
int length1 = 0, length2 = 0;
ListNode l1, l2;
//先获取两个链表长度
for(l1 = pHead1; l1 != null; l1 = l1.next)
length1++;
for(l2 = pHead2; l2 != null; l2 = l2.next)
length2++;
//让l1指向较长一个链表
if(length1 < length2) {
l1 = pHead2;
l2 = pHead1;
}
else {
l1 = pHead1;
l2 = pHead2;
}
for(int i = 0; i < Math.abs(length1 - length2); i++) //l1先移动长度差
l1 = l1.next;
while(l1 != l2) {
l1 = l1.next;
l2 = l2.next;
}
return l1;
}
}
题目描述
统计一个数字在排序数组中出现的次数。
public class Solution {
public int GetNumberOfK(int [] array , int k) {
//二分查找
int mid = binarySearch(array, k);
if(mid == -1)
return 0;
else { //查找成功,则向两边遍历计数
int count = 1;
int i = mid, j = mid;
while(i < array.length - 1 && array[++i] == k)
count++;
while(j > 0 && array[--j] == k)
count++;
return count;
}
}
public int binarySearch(int [] array , int k) {
int start = 0, end = array.length - 1;
while(start <= end) {
int mid = (start + end) / 2;
if(array[mid] == k)
return mid;
else if(array[mid] < k)
start = mid + 1;
else
end = mid - 1;
}
return -1;
}
}
题目描述
输入一棵二叉树,求该树的深度。从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度。
public class Solution {
public int TreeDepth(TreeNode root) {
if(root == null)
return 0;
else {
return 1 + Math.max(TreeDepth(root.left), TreeDepth(root.right));
}
}
}
题目描述
输入一棵二叉树,判断该二叉树是否是平衡二叉树。
public class Solution {
public boolean IsBalanced_Solution(TreeNode root) {
if(root == null)
return true;
//比较左右子树深度即可
int leftDepth = getDepth(root.left);
int rightDepth = getDepth(root.right);
if(Math.abs(leftDepth - rightDepth) > 1)
return false;
else
return IsBalanced_Solution(root.left) && IsBalanced_Solution(root.right);
}
public int getDepth(TreeNode root) {
if(root == null)
return 0;
else
return 1 + Math.max(getDepth(root.left), getDepth(root.right));
}
}
题目描述
一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。
//num1,num2分别为长度为1的数组。传出参数
//将num1[0],num2[0]设置为返回结果
public class Solution {
public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) {
int bitResult = 0;
//异或消去重复的数,最后得到bitResult是这两个数的异或
for(int i = 0; i < array.length; i++) {
bitResult ^= array[i];
}
int index = 0;
//从低位到高位找到这两个数第一个异或后为1,也就是第一个不同的数位
while(index < 32 && ((bitResult & 1) == 0)){
index++;
bitResult >>= 1;
}
//最后求一遍异或,根据不同位为1还是0分开,即可分别得到两个数
for(int i = 0; i < array.length; i++) {
if(((array[i] >> index) & 1) == 1)
num1[0] ^= array[i];
else
num2[0] ^= array[i];
}
}
}
题目描述
小明很喜欢数学,有一天他在做数学作业时,要求计算出9~16的和,他马上就写出了正确答案是100。但是他并不满足于此,他在想究竟有多少种连续的正数序列的和为100(至少包括两个数)。没多久,他就得到另一组连续正数和为100的序列:18,19,20,21,22。现在把问题交给你,你能不能也很快的找出所有和为S的连续正数序列? Good Luck!
输出描述:
输出所有和为S的连续正数序列。序列内按照从小至大的顺序,序列间按照开始数字从小到大的顺序
import java.util.ArrayList;
public class Solution {
public ArrayList > FindContinuousSequence(int sum) {
ArrayList > res = new ArrayList >();
if(sum <= 2)
return res;
int n = 2; //连续正数的个数为n
int mid = sum / n;
int first = mid + 1 - n / 2; //n为偶数的first计算公式,奇数没有+1
boolean nIsOdd = false;
while(first > 0) {
//n为奇数或偶数分别处理
if(nIsOdd && sum % n == 0) { //n为奇数时要能除开
//求和之后就是mid*n,一定是sum,不必再判断
ArrayList list = new ArrayList();
for(int i = 0; i < n; i++)
list.add(first + i);
res.add(0, list); //按题目要求顺序需要头部插入
}
if(!nIsOdd && sum % n != 0) { //n为偶数时不可以除开
//求和之后结果是mid*n+(last-mid),即mid*n+n/2
if(mid * n + n / 2 == sum) {
ArrayList list = new ArrayList();
for(int i = 0; i < n; i++)
list.add(first + i);
res.add(0, list);
}
}
//更新各个参数
n++;
nIsOdd = !nIsOdd;
mid = sum / n;
first = mid + 1 - n / 2;
if(nIsOdd) //n为奇数,first去掉+1
first--;
}
return res;
}
}
题目描述
输入一个递增排序的数组和一个数字S,在数组中查找两个数,使得他们的和正好是S,如果有多对数字的和等于S,输出两个数的乘积最小的。
输出描述:
对应每个测试案例,输出两个数,小的先输出。
import java.util.ArrayList;
public class Solution {
public ArrayList FindNumbersWithSum(int [] array,int sum) {
//乘积最小是最靠近两侧的结果
ArrayList res = new ArrayList();
if(array.length == 0)
return res;
int i = 0, j = array.length - 1; //从两侧向中间遍历
while(i < j) {
if(array[i] + array[j] == sum) {
res.add(array[i]);
res.add(array[j]);
break;
}
else if(array[i] + array[j] < sum)
i++;
else
j--;
}
return res;
}
}
题目描述
汇编语言中有一种移位指令叫做循环左移(ROL),现在有个简单的任务,就是用字符串模拟这个指令的运算结果。对于一个给定的字符序列S,请你把其循环左移K位后的序列输出。例如,字符序列S=”abcXYZdef”,要求输出循环左移3位后的结果,即“XYZdefabc”。是不是很简单?OK,搞定它!
public class Solution {
public String LeftRotateString(String str,int n) {
//先分两部分,再分别转置的解法
if(str == null || n > str.length())
return "";
String a = str.substring(0, n);
String b = str.substring(n);
return reverse(reverse(a) + reverse(b));
}
public String reverse(String str) {
String res = "";
for(int i = 0; i < str.length(); i++)
res = str.charAt(i) + res;
return res;
}
}
题目描述
牛客最近来了一个新员工Fish,每天早晨总是会拿着一本英文杂志,写些句子在本子上。同事Cat对Fish写的内容颇感兴趣,有一天他向Fish借来翻看,但却读不懂它的意思。例如,“student. a am I”。后来才意识到,这家伙原来把句子单词的顺序翻转了,正确的句子应该是“I am a student.”。Cat对一一的翻转这些单词顺序可不在行,你能帮助他么?
public class Solution {
public String ReverseSentence(String str) {
String[] strArr = str.split(" ");
if(strArr.length == 0)
return str; //原样返回
String res = "";
int i = 0, j = strArr.length - 1;
while(i < j) { //reverse
String temp = strArr[i];
strArr[i] = strArr[j];
strArr[j] = temp;
i++;
j--;
}
for(int k = 0; k < strArr.length - 1; k++)
res += strArr[k] + " ";
res += strArr[strArr.length - 1];
return res;
}
}
题目描述
LL今天心情特别好,因为他去买了一副扑克牌,发现里面居然有2个大王,2个小王(一副牌原本是54张^_^)...他随机从中抽出了5张牌,想测测自己的手气,看看能不能抽到顺子,如果抽到的话,他决定去买体育彩票,嘿嘿!!“红心A,黑桃3,小王,大王,方片5”,“Oh My God!”不是顺子.....LL不高兴了,他想了想,决定大\小 王可以看成任何数字,并且A看作1,J为11,Q为12,K为13。上面的5张牌就可以变成“1,2,3,4,5”(大小王分别看作2和4),“So Lucky!”。LL决定去买体育彩票啦。 现在,要求你使用这幅牌模拟上面的过程,然后告诉我们LL的运气如何, 如果牌能组成顺子就输出true,否则就输出false。为了方便起见,你可以认为大小王是0。
public class Solution {
public boolean isContinuous(int [] numbers) {
if(numbers.length != 5)
return false;
int[] pokers = new int[14];
int max = 1, min = 13;
for(int num : numbers) {
if(num == 0)
pokers[0]++;
else{
if(pokers[num] > 0) //出现重复
return false;
pokers[num]++;
if(num < min)
min = num;
if(num > max)
max = num;
}
}
if(pokers[0] == 4) //4个0一定可以
return true;
//否则只要没有重复,且最大最小值差在4以内即可
else if(max - min > 4)
return false;
return true;
}
}
题目描述
每年六一儿童节,牛客都会准备一些小礼物去看望孤儿院的小朋友,今年亦是如此。HF作为牛客的资深元老,自然也准备了一些小游戏。其中,有个游戏是这样的:首先,让小朋友们围成一个大圈。然后,他随机指定一个数m,让编号为0的小朋友开始报数。每次喊到m-1的那个小朋友要出列唱首歌,然后可以在礼品箱中任意的挑选礼物,并且不再回到圈中,从他的下一个小朋友开始,继续0...m-1报数....这样下去....直到剩下最后一个小朋友,可以不用表演,并且拿到牛客名贵的“名侦探柯南”典藏版(名额有限哦!!^_^)。请你试着想下,哪个小朋友会得到这份礼品呢?(注:小朋友的编号是从0到n-1)
public class Solution {
public int LastRemaining_Solution(int n, int m) {
//就是约瑟夫环
if(n == 0)
return -1;
int s = 0; //1人环中,就是0
for(int i = 2; i <= n; i++) { //2人环到n人环迭代
s = (s + m) % i;
}
return s;
}
}
题目描述
求1+2+3+...+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。
public class Solution {
public int Sum_Solution(int n) {
int res = n;
//利用&&的短路,前面为假后面不计算,构造递归出口
boolean a = (res > 0) && ((res += Sum_Solution(res - 1)) > 0);
return res;
}
}
题目描述
写一个函数,求两个整数之和,要求在函数体内不得使用+、-、*、/四则运算符号。
public class Solution {
public int Add(int num1,int num2) {
//直接加就可以
while(num2 != 0) {
int temp = num1 ^ num2; //求和不算进位
num2 = (num1 & num2) << 1; //进位
num1 = temp;
}
return num1;
}
}
题目描述
将一个字符串转换成一个整数(实现Integer.valueOf(string)的功能,但是string不符合数字要求时返回0),要求不能使用字符串转换整数的库函数。 数值为0或者字符串不是一个合法的数值则返回0。
输入描述:
输入一个字符串,包括数字字母符号,可以为空
输出描述:
如果是合法的数值表达则返回该数字,否则返回0
public class Solution {
public int StrToInt(String str) {
if(str == null || str.length() == 0)
return 0;
int res = 0;
int weight = 1;
if(str.charAt(0) == '-') //负数
weight = -1;
for(int i = str.length() - 1; i >= 0; i--) { //从右向左遍历
char c = str.charAt(i);
if(c >= '0' && c <= '9') {
int temp = res + (c - '0') * weight;
if(temp - res != (c - '0') * weight) //溢出
return 0;
else
res = temp;
}
else if((c == '+' || c == '-') && i == 0) //不是0-9只能是第1位+-号,否则非法
break;
else
return 0;
weight *= 10;
}
return res;
}
}
题目描述
在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任意一个重复的数字。 例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是第一个重复的数字2。
public class Solution {
// 这里要特别注意~返回任意重复的一个,赋值duplication[0]
// Return value: true if the input is valid, and there are some duplications in the array number
// otherwise false
public boolean duplicate(int numbers[],int length,int [] duplication) {
//这个题应该利用下标
if(length <= 1)
return false;
int j = 0; //下标为j,初始不能是值和下标相同的,否则跳不出去会产生错误结果
while(numbers[j] == j) //找到一个符合要求的初始点
j++;
j = numbers[j]; //这一步至关重要,要知道初始下标j不是跳到的,不能置-1
//所以要改为跳到的第一个下标
//计算值和下标相同的个数,循环次数要减掉才行
int count = 0;
for(int i = 0; i < length; i++)
if(numbers[i] == i)
count++;
for(int i = 0; i < length - count; i++) { //此处i只是次数,与下标无关
if(numbers[j] == -1 || numbers[j] == j) { //第二个条件重要!跳到陷阱处也说明是重复
duplication[0] = j;
return true;
}
else {
int temp = j;
j = numbers[j];
numbers[temp] = -1; //跳到过的置-1
}
return false;
}
}
题目描述
给定一个数组A[0,1,...,n-1],请构建一个数组B[0,1,...,n-1],其中B中的元素B[i]=A[0]*A[1]*...*A[i-1]*A[i+1]*...*A[n-1]。不能使用除法。
public class Solution {
public int[] multiply(int[] A) {
//遍历一个来回,逐个填充乘进结果数组,用一个变量储存乘积即可
int[] res = new int[A.length];
int left = 1;
int right = 1;
for(int i = 0; i < A.length; i++) {
res[i] = left;
left *= A[i];
}
for(int i = A.length - 1; i >= 0; i--) {
res[i] *= right;
right *= A[i];
}
return res;
}
}
题目描述
请实现一个函数用来匹配包括'.'和'*'的正则表达式。模式中的字符'.'表示任意一个字符,而'*'表示它前面的字符可以出现任意次(包含0次)。 在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串"aaa"与模式"a.a"和"ab*ac*a"匹配,但是与"aa.a"和"ab*a"均不匹配
public class Solution {
public boolean match(char[] str, char[] pattern) {
return match(str, 0, pattern, 0);
}
//加上开始下标参数,以便递归处理'*'的复杂情况
public boolean match(char[] str, int i1, char[] pattern, int i2) {
if(i1 == str.length && i2 == pattern.length) //都遍历完,返回true
return true;
else if(i2 == pattern.length) //pattern结束,str还没结束当然不行
return false;
else if(i1 == str.length) { //str结束,pattern剩下的只能是字符+'*'的组合
while(i2 + 1 < pattern.length && pattern[i2 + 1] == '*')
i2 += 2;
return i2 == pattern.length;
}
//两个都没结束的情况
//pattern后面是'*'时
if(i2 + 1 < pattern.length && pattern[i2 + 1] == '*') {
if(str[i1] == pattern[i2] || pattern[i2] == '.') //'*'代表1次或多次,或0次
//0次不要丢掉!因为pattern后面可能有普通字符需要匹配str中字符
//如果丢了0次'.'把str中的匹配掉了,pattern后面就没处匹配了,如"bbbba"和".*a*a"
return match(str, i1 + 1, pattern, i2 + 2) ||
match(str, i1 + 1, pattern, i2) ||
match(str, i1, pattern, i2 + 2);
else //'*'代表0次
return match(str, i1, pattern, i2 + 2);
}
//pattern后面不是'*'时
else {
if(str[i1] == pattern[i2] || pattern[i2] == '.')
return match(str, i1 + 1, pattern, i2 + 1);
else
return false;
}
}
}
题目描述
请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。例如,字符串"+100","5e2","-123","3.1416"和"-1E-16"都表示数值。 但是"12e","1a3.14","1.2.3","+-5"和"12e+4.3"都不是。
public class Solution {
public boolean isNumeric(char[] str) {
boolean noPoint = true; //是否没有'.'
boolean noE = true; //是否没有'E'或'e'
int pointPos = 0;
int ePos = 0;
for(int i = 0; i < str.length; i++) {
if(str[i] == '.') {
if(noPoint) {
noPoint = false;
pointPos = i;
}
else //两个.
return false;
}
if(str[i] == 'e' || str[i] == 'E') {
if(noE) {
noE = false;
ePos = i;
}
else //两个e
return false;
}
}
if(!noE) { //有e
if(pointPos > ePos)
return false;
else
return isInteger(str, ePos + 1, str.length - 1) && isFloatOrInteger(str, 0, ePos - 1);
}
else
return isFloatOrInteger(str, 0, str.length - 1);
}
public boolean isNum(char c) {
return c >= '0' && c <= '9';
}
public boolean isInteger(char[] str, int start, int end) {
if(start > end)
return false;
if(start == end)
return isNum(str[start]);
if(str[start] == '+' || str[start] == '-')
start++;
while(start <= end) {
if(!isNum(str[start]))
break;
else
start++;
}
if(start == end + 1)
return true;
else
return false;
}
//这个函数包括整数判断,整数也返回true
public boolean isFloatOrInteger(char[] str, int start, int end) {
if(start > end)
return false;
if(start == end)
return isNum(str[start]);
if(str[start] == '+' || str[start] == '-')
start++;
while(start <= end) {
if(!isNum(str[start]) && str[start] != '.') //和isInteger只有这一处有区别,
break; //不用担心‘.’超过一个因为主函数判断过了
else
start++;
}
if(start == end + 1)
return true;
else
return false;
}
}
题目描述
请实现一个函数用来找出字符流中第一个只出现一次的字符。例如,当从字符流中只读出前两个字符"go"时,第一个只出现一次的字符是"g"。当从该字符流中读出前六个字符“google"时,第一个只出现一次的字符是"l"。
输出描述:
如果当前字符流没有存在出现一次的字符,返回#字符。
public class Solution {
String s = "";
int[] charNums = new int[256];
//Insert one char from stringstream
public void Insert(char ch) {
s += ch;
charNums[ch]++;
}
//return the first appearence once char in current stringstream
public char FirstAppearingOnce() {
//从字符串s开始遍历
for(int i = 0; i < s.length(); i++)
if(charNums[s.charAt(i)] == 1)
return s.charAt(i);
return '#';
}
}
题目描述
给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null。
public class Solution {
public ListNode EntryNodeOfLoop(ListNode pHead) {
if(pHead == null)
return null;
else if(pHead.next == null)
return null;
ListNode fast = pHead, slow = pHead, start = pHead;
while(fast != null) {
if(fast.next != null)
fast = fast.next.next;
else
fast = fast.next; //此时fast已经为null
slow = slow.next;
if(fast == slow) { //相等处fast多走了整数个环长,也是slow走的长度
while(start != slow) { //再走1个环外长度就刚好会遇到
start = start.next;
slow = slow.next;
}
break;
}
}
if(fast == null) //无环
return null;
else
return start;
}
}
题目描述
在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。 例如,链表1->2->3->3->4->4->5 处理后为 1->2->5
public class Solution {
public ListNode deleteDuplication(ListNode pHead) {
if(pHead == null)
return null;
ListNode res = new ListNode(0); //pHead是可能被删掉的,所以要保存一个头节点
res.next = pHead;
ListNode pre = res; //前置节点,删除时会用到
ListNode l = pHead;
int cur = pHead.val;
while(l != null) {
int count = 0;
while(l != null && l.val == cur) { //统计相同元素个数
l = l.next;
count++;
}
if(count > 1)
pre.next = l; //越过重复值的节点,注意pre不动
else
pre = pre.next; //后移
if(l != null)
cur = l.val; //更新cur
}
return res.next;
}
}
题目描述
给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。
/*
public class TreeLinkNode {
int val;
TreeLinkNode left = null;
TreeLinkNode right = null;
TreeLinkNode next = null;
TreeLinkNode(int val) {
this.val = val;
}
}
*/
public class Solution {
public TreeLinkNode GetNext(TreeLinkNode pNode) {
if(pNode == null)
return null;
if(pNode.right != null)
return inOrderFirstNode(pNode.right);
//pNode右为空,则当前子树已经遍历完
TreeLinkNode father = pNode.next;
//要用循环才行
while(father != null) {
if(father.left == pNode)
return father;
//否则就是father为根的子树也遍历完
else {
pNode = father;
father = father.next;
}
}
return null;
}
//求中序遍历的第一个节点
public TreeLinkNode inOrderFirstNode(TreeLinkNode root) {
//调用时让这个函数输入不为空,不包含返回空的情况,便于理解
if(root.left == null)
return root;
else
return inOrderFirstNode(root.left);
}
}
题目描述
请实现一个函数,用来判断一颗二叉树是不是对称的。注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的。
public class Solution {
boolean isSymmetrical(TreeNode pRoot) {
if(pRoot == null)
return true;
else //左右子树互为镜像即对称
return isMirror(pRoot.left, pRoot.right);
}
//判断是否是镜像
boolean isMirror(TreeNode root1, TreeNode root2) {
if(root1 == null && root2 == null)
return true;
else if(root1 == null || root2 == null)
return false;
if(root1.val != root2.val)
return false;
else
return isMirror(root1.left, root2.right) && isMirror(root1.right, root2.left);
}
}
题目描述
请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推。
import java.util.ArrayList;
import java.util.Queue;
import java.util.LinkedList;
public class Solution {
public ArrayList > Print(TreeNode pRoot) {
//还是层次遍历
//和逐行打印相同,只是新增加一个变量标记,偶数行要逆序
ArrayList > res = new ArrayList >();
if(pRoot == null)
return res;
Queue queue = new LinkedList();
queue.offer(pRoot);
TreeNode mark = new TreeNode(0);
queue.offer(mark);
ArrayList list = new ArrayList();
boolean reverse = false; //逆序标记,偶数行为true
while(!queue.isEmpty()) {
TreeNode cur = queue.poll();
if(cur == mark) //一定要判断是不是最后一个mark
break;
if(reverse) //逆序,在头部插入
list.add(0, cur.val);
else
list.add(cur.val);
boolean isLast = false;
if(queue.peek() == mark) { //当前层最后一个节点
res.add(list);
list = new ArrayList();
isLast = true;
queue.poll(); //mark标记出队,因此除最后一个mark外不会出现cur == mark
reverse = !reverse; //标记更改
}
if(cur.left != null)
queue.offer(cur.left);
if(cur.right != null)
queue.offer(cur.right);
if(isLast) //当前层最后一个节点,mark标记入队
queue.offer(mark);
}
if(list.size() > 0) //最后的list非空才添加
res.add(list);
return res;
}
}
题目描述
从上到下按层打印二叉树,同一层结点从左至右输出。每一层输出一行。
import java.util.ArrayList;
import java.util.Queue;
import java.util.LinkedList;
public class Solution {
ArrayList > Print(TreeNode pRoot) {
//还是层次遍历
//需要额外储存每一层结束时的标记,新建一个TreeNode作为标记
//下一层入队列时如果是当前层最后一个,则右节点之后添加标记
ArrayList > res = new ArrayList >();
if(pRoot == null)
return res;
Queue queue = new LinkedList();
queue.offer(pRoot);
TreeNode mark = new TreeNode(0);
queue.offer(mark);
ArrayList list = new ArrayList();
while(!queue.isEmpty()) {
TreeNode cur = queue.poll();
if(cur == mark) //一定要判断是不是最后一个mark
break;
list.add(cur.val);
boolean isLast = false;
if(queue.peek() == mark) { //当前层最后一个节点
res.add(list);
list = new ArrayList();
isLast = true;
queue.poll(); //mark标记出队,因此除最后一个mark外不会出现cur == mark
}
if(cur.left != null)
queue.offer(cur.left);
if(cur.right != null)
queue.offer(cur.right);
if(isLast) //当前层最后一个节点,mark标记入队
queue.offer(mark);
}
if(list.size() > 0) //最后的list非空才添加
res.add(list);
return res;
}
}
题目描述
请实现两个函数,分别用来序列化和反序列化二叉树
public class Solution {
String Serialize(TreeNode root) {
//前序遍历序列化,","分隔节点,"#"表示null
String res = "";
if(root == null) {
res += "#,";
return res;
}
res += root.val + ",";
res += Serialize(root.left);
res += Serialize(root.right);
return res;
}
TreeNode Deserialize(String str) {
if(str == null)
return null;
String[] strArr = str.split(","); //获取节点String数组
int[] index = new int[]{-1};
return DeserializeStrArr(strArr, index);
}
TreeNode DeserializeStrArr(String[] strArr, int[] index) {
//一定要最先修改index,因为递归1次就检查了1个节点,index要后移
//这样可以保证每次递归的index都是不同的
index[0]++;
TreeNode root = null;
if(!strArr[index[0]].equals("#")) { //非null节点
root = new TreeNode(Integer.valueOf(strArr[index[0]]));
root.left = DeserializeStrArr(strArr, index);
root.right = DeserializeStrArr(strArr, index);
}
return root;
}
}
题目描述
给定一棵二叉搜索树,请找出其中的第k小的结点。例如, (5,3,7,2,4,6,8) 中,按结点数值大小顺序第三小结点的值为4。
import java.util.ArrayList;
public class Solution {
TreeNode KthNode(TreeNode pRoot, int k) {
//中序遍历,得到升序数组,数到k即可
if(k <= 0)
return null;
ArrayList list = new ArrayList();
inOrder(pRoot, k, list);
if(list.size() >= k) //因为递归的原因,还是可能会遍历到size>k,一定要判断>
return list.get(k - 1);
else
return null;
}
void inOrder(TreeNode pRoot, int k, ArrayList list) {
if(list.size() >= k) //不需要遍历到超过k
return;
if(pRoot != null) {
inOrder(pRoot.left, k, list);
list.add(pRoot);
inOrder(pRoot.right, k, list);
}
}
}
题目描述
如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。我们使用Insert()方法读取数据流,使用GetMedian()方法获取当前读取数据的中位数。
import java.util.ArrayList;
public class Solution {
ArrayList list = new ArrayList(); //有序列表
public void Insert(Integer num) {
//插入排序
if(list.size() == 0) {
list.add(num);
return;
}
if(num > list.get(list.size() - 1))
list.add(num);
else {
int i = list.size() - 1;
while(i >= 0 && num <= list.get(i))
i--;
list.add(i + 1, num);
}
}
public Double GetMedian() {
int size = list.size();
if(size == 0)
return null;
else if(size % 2 == 1)
return new Double(list.get((size - 1) / 2) * 1.0); //注意下标和size的关系,别忘了-1
else
return new Double((list.get((size - 1) / 2) + list.get((size - 1) / 2 + 1)) / 2.0);
}
}
题目描述
给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值。例如,如果输入数组{2,3,4,2,6,2,5,1}及滑动窗口的大小3,那么一共存在6个滑动窗口,他们的最大值分别为{4,4,6,6,6,5}; 针对数组{2,3,4,2,6,2,5,1}的滑动窗口有以下6个: {[2,3,4],2,6,2,5,1}, {2,[3,4,2],6,2,5,1}, {2,3,[4,2,6],2,5,1}, {2,3,4,[2,6,2],5,1}, {2,3,4,2,[6,2,5],1}, {2,3,4,2,6,[2,5,1]}。
import java.util.ArrayList;
import java.util.Queue;
import java.util.LinkedList;
public class Solution {
public ArrayList maxInWindows(int [] num, int size) {
ArrayList res = new ArrayList();
if(size <= 0 || size > num.length)
return res;
Queue queue = new LinkedList(); //保持队列大小为size,更新max
int maxIndex = 0, max = Integer.MIN_VALUE;
for(int i = 0; i < num.length; i++) {
if(queue.size() < size) { //初始队列没满的时候
queue.offer(num[i]);
if(num[i] >= max) { //要加上等于,以便maxIndex更新到右边第一个max位置
max = num[i];
maxIndex = i;
}
}
else {
res.add(max); //先储存max
//看出队的是不是当前max,用下标判断
if(maxIndex == i - size) { //出队的是当前max
max = num[i - size + 1];
maxIndex = i - size + 1;
for(int j = i - size + 2; j <= i; j++) //循环取得新max
if(num[j] >= max) {
max = num[j];
maxIndex = j;
}
}
//如果不是,就不用管出队的值,只有新值num[i]>=max时更新max即可
else if(num[i] >= max) { //当前为最大值,更新max和maxIndex
max = num[i];
maxIndex = i;
}
queue.poll(); //无论前面如何都要出队和入队
queue.offer(num[i]);
}
}
res.add(max);
return res;
}
}
题目描述
请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一个格子开始,每一步可以在矩阵中向左,向右,向上,向下移动一个格子。如果一条路径经过了矩阵中的某一个格子,则之后不能再次进入这个格子。 例如 a b c e s f c s a d e e 这样的3 X 4 矩阵中包含一条字符串"bcced"的路径,但是矩阵中不包含"abcb"路径,因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入该格子。
public class Solution {
public boolean hasPath(char[] matrix, int rows, int cols, char[] str) {
for(int i = 0; i < matrix.length; i++) { //不同的起始点
boolean[] flag = new boolean[matrix.length]; //每个起始点新建标记数组
if(backtracking(i, matrix, rows, cols, str, 0, flag))
return true;
}
return false;
}
//回溯算法
public boolean backtracking(int start, char[] matrix, int rows, int cols,
char[] str, int strIndex, boolean[] flag) {
if(strIndex == str.length) //字符串比较完成
return true;
if(start < 0 || start >= matrix.length || flag[start] || matrix[start] != str[strIndex])
return false;
else { //求上下左右的坐标
flag[start] = true;
int left = start % cols == 0 ? -1 : start - 1; //是否是每行开始
int right = (start + 1) % cols == 0 ? -1 : start + 1; //是否是每行结束
int up = start - cols;
int down = start + cols;
return backtracking(left, matrix, rows, cols, str, strIndex + 1, flag)
|| backtracking(right, matrix, rows, cols, str, strIndex + 1, flag)
|| backtracking(up, matrix, rows, cols, str, strIndex + 1, flag)
|| backtracking(down, matrix, rows, cols, str, strIndex + 1, flag);
}
}
}
题目描述
地上有一个m行和n列的方格。一个机器人从坐标0,0的格子开始移动,每一次只能向左,右,上,下四个方向移动一格,但是不能进入行坐标和列坐标的数位之和大于k的格子。 例如,当k为18时,机器人能够进入方格(35,37),因为3+5+3+7 = 18。但是,它不能进入方格(35,38),因为3+5+3+8 = 19。请问该机器人能够达到多少个格子?
public class Solution {
public int movingCount(int threshold, int rows, int cols) {
boolean[][] flag = new boolean[rows][cols]; //标记是否走过
return backtracking(0, 0, threshold, rows, cols, flag);
}
//回溯算法
public int backtracking(int i, int j, int threshold, int rows, int cols, boolean[][] flag) {
if(i < 0 || i >= rows || j < 0 || j >= cols || digitAdd(i, j) > threshold || flag[i][j])
return 0;
else {
flag[i][j] = true;
return 1 + backtracking(i - 1, j, threshold, rows, cols, flag)
+ backtracking(i + 1, j, threshold, rows, cols, flag)
+ backtracking(i, j - 1, threshold, rows, cols, flag)
+ backtracking(i, j + 1, threshold, rows, cols, flag);
}
}
//数位求和
public int digitAdd(int a, int b) {
int sum = 0;
while(a > 0) {
sum += a % 10;
a /= 10;
}
while(b > 0) {
sum += b % 10;
b /= 10;
}
return sum;
}
}