《剑指offer》牛客网41-60

41.和为S的连续正数序列

题目描述

小明很喜欢数学,有一天他在做数学作业时,要求计算出9~16的和,他马上就写出了正确答案是100。但是他并不满足于此,他在想究竟有多少种连续的正数序列的和为100(至少包括两个数)。没多久,他就得到另一组连续正数和为100的序列:18,19,20,21,22。现在把问题交给你,你能不能也很快的找出所有和为S的连续正数序列? Good Luck!
输出描述:
输出所有和为S的连续正数序列。序列内按照从小至大的顺序,序列间按照开始数字从小到大的顺序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
public static ArrayList<ArrayList<Integer>> findContinuousSequence(int sum) {
ArrayList<ArrayList<Integer>> arrayList = new ArrayList<ArrayList<Integer>>();
if (sum <= 2) {
return arrayList;
}

int start = 1;
int end = 2;

while (start != (sum + 1) / 2) {
int currentSum = sumOfList(start, end);
if (currentSum == sum) {
ArrayList<Integer> list = new ArrayList<>();
for (int i = start; i <= end; i++) {
list.add(i);
}
arrayList.add(list);
start++;
end++;
} else if (currentSum < sum) {
end++;
} else {
start++;
}
}

return arrayList;
}

public static int sumOfList(int start, int end) { //计算当前序列的和
int sum = start;
for (int i = start + 1; i <= end; i++) {
sum += i;
}
return sum;
}

42.和为S的两个数字

题目描述
输入一个递增排序的数组和一个数字S,在数组中查找两个数,使得他们的和正好是S,如果有多对数字的和等于S,输出两个数的乘积最小的。
输出描述:
对应每个测试案例,输出两个数,小的先输出。
浅谈Arrays.asList()方法的使用
 首先,该方法是将数组转化为list。有以下几点需要注意:
  (1)该方法不适用于基本数据类型(byte,short,int,long,float,double,boolean)
  (2)该方法将数组与列表链接起来,当更新其中之一时,另一个自动更新
(3)不支持add和remove方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import java.util.ArrayList;
import java.util.Arrays;
public class Solution {
public ArrayList<Integer> FindNumbersWithSum(int [] array,int sum) {
int i=0,j=array.length-1;
while(i<j){
int cursum=array[i]+array[j];
if(cursum==sum)
return new ArrayList<>(Arrays.asList(array[i],array[j]));
if(cursum<sum)
i++;
else
j--;
}
return new ArrayList<>();
}
}

43.左旋转字符串

题目描述
汇编语言中有一种移位指令叫做循环左移(ROL),现在有个简单的任务,就是用字符串模拟这个指令的运算结果。对于一个给定的字符序列S,请你把其循环左移K位后的序列输出。例如,字符序列S=”abcXYZdef”,要求输出循环左移3位后的结果,即“XYZdefabc”。是不是很简单?OK,搞定它!

public class Solution {
public String LeftRotateString(String str,int n) {
if(str.length()<=1)
return “”;
char[]chars=str.toCharArray();
reverse(chars,0,n-1);
reverse(chars,n,chars.length-1);
reverse(chars,0,chars.length-1);
return new String(chars);

}
public void reverse(char[]c,int low,int high){
    while(low<high){
        char temp =c[low];
        c[low]=c[high];
        c[high]=temp;
        low++;
        high--;
    }

}

}

44.翻转单词顺序列

题目描述
汇编语言中有一种移位指令叫做循环左移(ROL),现在有个简单的任务,就是用字符串模拟这个指令的运算结果。对于一个给定的字符序列S,请你把其循环左移K位后的序列输出。例如,字符序列S=”abcXYZdef”,要求输出循环左移3位后的结果,即“XYZdefabc”。是不是很简单?OK,搞定它!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class Solution {
public String LeftRotateString(String str,int n) {
if(str.length()<=1)
return "";
char[]chars=str.toCharArray();
reverse(chars,0,n-1);
reverse(chars,n,chars.length-1);
reverse(chars,0,chars.length-1);
return new String(chars);



}
public void reverse(char[]c,int low,int high){
while(low<high){
char temp =c[low];
c[low]=c[high];
c[high]=temp;
low++;
high--;
}

}

}

45.扑克牌顺子

题目描述
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。

45.扑克牌顺子

题目描述
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。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import java.util.Arrays;
public class Solution {
public boolean isContinuous(int [] num) {
if(num.length<5)
return false;
Arrays.sort(num);
int count =0;
for(int nums:num){
if(nums==0)
count++;
}
for(int i=count;i<num.length-1;i++){
if(num[i+1]==num[i])
return false;
count-=num[i+1]-num[i]-1;
}
return count>=0;

}

}

46.孩子们的游戏(圆圈中最后剩下的数)

题目描述
每年六一儿童节,牛客都会准备一些小礼物去看望孤儿院的小朋友,今年亦是如此。HF作为牛客的资深元老,自然也准备了一些小游戏。其中,有个游戏是这样的:首先,让小朋友们围成一个大圈。然后,他随机指定一个数m,让编号为0的小朋友开始报数。每次喊到m-1的那个小朋友要出列唱首歌,然后可以在礼品箱中任意的挑选礼物,并且不再回到圈中,从他的下一个小朋友开始,继续0…m-1报数….这样下去….直到剩下最后一个小朋友,可以不用表演,并且拿到牛客名贵的“名侦探柯南”典藏版(名额有限哦!!^_^)。请你试着想下,哪个小朋友会得到这份礼品呢?(注:小朋友的编号是从0到n-1)

如果没有小朋友,请返回-1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
class ListNode {

int val;
ListNode next = null;

ListNode(int val) {
this.val = val;
}

}

public class Solution {

public int LastRemaining_Solution(int n, int m) {

if (n <= 0 || m <= 0) {
return -1;
}

ListNode head = new ListNode(0);
ListNode node = head;
for (int i = 1; i < n; i++) {
node.next = new ListNode(i);
node = node.next;
}
node.next = head;

int k = 0;
while (node.next != node) {
if (++k == m) {
node.next = node.next.next;
k = 0;
} else {
node = node.next;
}
}

return node.val;
}

}

47.求1+2+3+…+n

题目描述
求1+2+3+…+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。

1
2
3
4
5
6
public class Solution {
public int Sum_Solution(int n) {
int sum=(int)Math.pow(n, 2)+n;
return sum>>1;
}
}

48.不用加减乘除做加法

题目描述
写一个函数,求两个整数之和,要求在函数体内不得使用+、-、*、/四则运算符号。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class Solution {
public int Add(int num1,int num2) {
//相加各位 + 计算进位
//十进制思想
//5+7 各位相加:2 进位:10
//2+10 12 0
//12+0
//二进制计算过程
//5+7 各位相加:101^111=010 进位:101&111=101 (<<1=1010)
//2+10 各位相加:010^1010=1000 进位:010&1010=010 <<1=0100
//8+4 1000^0100=1100 1000&0100=0
//12+0
return num2==0? num1:Add(num1^num2,(num1&num2)<<1);
}
}

49.把字符串转换成整数

题目描述
将一个字符串转换成一个整数,要求不能使用字符串转换整数的库函数。 数值为0或者字符串不是一个合法的数值则返回0
输入描述:
输入一个字符串,包括数字字母符号,可以为空
输出描述:
如果是合法的数值表达则返回该数字,否则返回0
示例1
输入
+2147483647
1a33
输出
2147483647
0

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
public class Solution {
public int StrToInt(String str) {
if (str.length() == 0 || "".equals(str)) {
return 0;
}
boolean isNeg = false;
if (str.charAt(0) == '+') {
str = str.substring(1);
} else if (str.charAt(0) == '-') {
isNeg = true;
str = str.substring(1);
}
char[] s = str.toCharArray();
double res = 0;
for (int i = 0; i < s.length; i++) {
if (!Character.isDigit(s[i])) {
return 0;
} else {
res += Math.pow(10, s.length - i - 1) * (s[i] - 48);
}
}
if(isNeg==false) {
if(res>Integer.MAX_VALUE) {
return 0;
}else {
return (int)res;
}
}else {
if((0-res)<Integer.MIN_VALUE) {
return 0;
}else {
return (int)(0-res);
}
}
}
}

50.数组中重复的数字

题目描述
在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任意一个重复的数字。 例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是第一个重复的数字2。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class Solution {
// Parameters:
// numbers: an array of integers
// length: the length of array numbers
// duplication: (Output) the duplicated number in the array number,length of duplication array is 1,so using duplication[0] = ? in implementation;
// Here duplication like pointor in C/C++, duplication[0] equal *duplication in C/C++
// 这里要特别注意~返回任意重复的一个,赋值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) {
for(int i=0;i<length;i++){
int temp;
int nums=0;
while(numbers[i]!=i){
if(numbers[numbers[i]]==numbers[i]){
duplication[0]=numbers[i];
return true;
}else{
temp=numbers[i];
numbers[i]=numbers[temp];
numbers[temp]=temp;
}
}
}
return false;
}
}

51.构建乘积数组

题目描述
给定一个数组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]。不能使用除法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class Solution {
public int[] multiply(int[] A) {
int[] B = new int[A.length];
int temp = 0;
for (int i = 0; i < A.length; i++) {
temp = A[i];
A[i] = 1;
B[i] = 1;
for (int j = 0; j < A.length; j++) {
B[i] *= A[j];
}
A[i] = temp;
}
return B;
}
}

52.正则表达式匹配

题目描述
请实现一个函数用来匹配包括’.’和’‘的正则表达式。模式中的字符’.’表示任意一个字符,而’‘表示它前面的字符可以出现任意次(包含0次)。 在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串”aaa”与模式”a.a”和”abaca”匹配,但是与”aa.a”和”ab*a”均不匹配

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public class Solution {
public boolean matchStr(char[] str, int i, char[] pattern, int j) {
// 边界
if (i == str.length && j == pattern.length) { // 字符串和模式串都为空
return true;
}
else if (j == pattern.length) { // 模式串为空
return false;
}

boolean flag = false;
boolean next = (j + 1 < pattern.length && pattern[j + 1] == '*'); // 模式串下一个字符是'*'
if (next) {
if (i < str.length && (pattern[j] == '.' || str[i] == pattern[j])) { // 要保证i<str.length,否则越界
return matchStr(str, i, pattern, j + 2) || matchStr(str, i + 1, pattern, j);
} else {
return matchStr(str, i, pattern, j + 2);
}
} else {
if (i < str.length && (pattern[j] == '.' || str[i] == pattern[j])) {
return matchStr(str, i + 1, pattern, j + 1);
} else {
return false;
}
}

}

public boolean match(char[] str, char[] pattern) {
return matchStr(str, 0, pattern, 0);
}

}

53.表示数值的字符串

题目描述
请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。例如,字符串”+100”,”5e2”,”-123”,”3.1416”和”-1E-16”都表示数值。 但是”12e”,”1a3.14”,”1.2.3”,”+-5”和”12e+4.3”都不是。

/*
思路:首先要想到所有的情况,然后进行分类讨论。-123.45e-67

+-号后面必定为数字或后面为.(-.123 = -0.123)
+-号只出现在第一位或在eE的后一位
.后面必定为数字或为最后一位(233. = 233.0)
eE后面必定为数字或+-号 

*/

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
public class Solution {
public boolean isNumeric(char[] str) {
boolean point = false, exp = false; // 标志小数点和指数

for (int i = 0; i < str.length; i++) {
if (str[i] == '+' || str[i] == '-') {
if (i + 1 == str.length || !(str[i + 1] >= '0' && str[i + 1] <= '9' || str[i + 1] == '.')) { // +-号后面必定为数字 或 后面为.(-.123 = -0.123)
return false;
}
if (!(i == 0 || str[i-1] == 'e' || str[i-1] == 'E')) { // +-号只出现在第一位或eE的后一位
return false;
}



} else if (str[i] == '.') {
if (point || exp || !(i + 1 < str.length && str[i + 1] >= '0' && str[i + 1] <= '9')) { // .后面必定为数字 或为最后一位(233. = 233.0)
return false;
}
point = true;

} else if (str[i] == 'e' || str[i] == 'E') {
if (exp || i + 1 == str.length || !(str[i + 1] >= '0' && str[i + 1] <= '9' || str[i + 1] == '+' || str[i + 1] == '-')) { // eE后面必定为数字或+-号
return false;
}
exp = true;

} else if (str[i] >= '0' && str[i] <= '9') {



} else {
return false;
}

}
return true;
}

}

54.字符流中第一个不重复的字符

题目描述
请实现一个函数用来找出字符流中第一个只出现一次的字符。例如,当从字符流中只读出前两个字符”go”时,第一个只出现一次的字符是”g”。当从该字符流中读出前六个字符“google”时,第一个只出现一次的字符是”l”。
输出描述:
如果当前字符流没有存在出现一次的字符,返回#字符。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class Solution {

int[] count = new int[256]; // 字符出现的次数
int[] index = new int[256]; // 字符出现的次数
int number = 0;

public void Insert(char ch) {
count[ch]++;
index[ch] = number++;
}

public char FirstAppearingOnce() {
int minIndex = number;
char ch = '#';
for (int i = 0; i < 256; i++) { // !!!
if (count[i] == 1 && index[i] < minIndex) {
ch = (char) i;
minIndex = index[i];
}
}
return ch;
}

}

55.链表中环的入口结点

题目描述
给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
/*
public class ListNode {
int val;
ListNode next = null;

ListNode(int val) {
this.val = val;
}

}
*/
public class Solution {

public ListNode EntryNodeOfLoop(ListNode pHead)
{
if(pHead==null||pHead.next==null){
return null;
}
ListNode slow=pHead;
ListNode fast=pHead;
do{
fast=fast.next.next;
slow=slow.next;
}while(slow!=fast);
fast=pHead;
while(fast!=slow){
slow=slow.next;
fast=fast.next;
}
return slow;

}

}

56.删除链表中重复的结点

题目描述
在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。 例如,链表1->2->3->3->4->4->5 处理后为 1->2->5

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public class Solution {
public ListNode deleteDuplication(ListNode pHead){
if(pHead == null || pHead.next == null){
return pHead;
}
// 自己构建辅助头结点
ListNode head = new ListNode(Integer.MIN_VALUE);
head.next = pHead;
ListNode pre = head;
ListNode cur = head.next;
while(cur!=null){
if(cur.next != null && cur.next.val == cur.val){
// 相同结点一直前进
while(cur.next != null && cur.next.val == cur.val){
cur = cur.next;
}
// 退出循环时,cur 指向重复值,也需要删除,而 cur.next 指向第一个不重复的值
// cur 继续前进
cur = cur.next;
// pre 连接新结点
pre.next = cur;
}else{
pre = cur;
cur = cur.next;
}
}
return head.next;
}
}

57.二叉树的下一个结点

题目描述
给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
/*
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.right!=null){
TreeLinkNode node=pNode.right;
while(node.left!=null)
node=node.left;
return node;
}else{
while(pNode.next!=null){
TreeLinkNode parent=pNode.next;
if(parent.left==pNode)
return parent;
pNode=pNode.next;
}
}
return null;
}
}

58.对称的二叉树

题目描述
请实现一个函数,用来判断一颗二叉树是不是对称的。注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/*
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;

public TreeNode(int val) {
this.val = val;

}

}
*/
public class Solution {
boolean isSymmetrical(TreeNode pRoot)
{
if(pRoot==null)
return true;
return isSymmetrical(pRoot.left,pRoot.right);
}
boolean isSymmetrical(TreeNode t1,TreeNode t2){
if(t1==null&&t2==null)
return true;
if(t1==null||t2==null)
return false;
if(t1.val!=t2.val)
return false;
return isSymmetrical(t1.left,t2.right)&&isSymmetrical(t1.right,t2.left);
}

}

59.按之字形顺序打印二叉树

题目描述
请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import java.util.ArrayList;

/*
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;

public TreeNode(int val) {
this.val = val;

}

}
*/
import java.util.LinkedList;
public class Solution {
public ArrayList<ArrayList<Integer> > Print(TreeNode pRoot) {
LinkedList<TreeNode> q = new LinkedList<>();
ArrayList<ArrayList<Integer>> res = new ArrayList<>();
boolean rev = true;
q.add(pRoot);
while(!q.isEmpty()){
int size = q.size();
ArrayList<Integer> list = new ArrayList<>();
for(int i=0; i<size; i++){
TreeNode node = q.poll();
if(node == null){continue;}
if(rev){
list.add(node.val);
}else{
list.add(0, node.val);
}
q.offer(node.left);
q.offer(node.right);
}
if(list.size()!=0){res.add(list);}
rev=!rev;
}
return res;
}
}

60.把二叉树打印成多行

题目描述
从上到下按层打印二叉树,同一层结点从左至右输出。每一层输出一行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
import java.util.*;
/*
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;

public TreeNode(int val) {
this.val = val;

}

}
*/
public class Solution {
ArrayList<ArrayList<Integer>> Print(TreeNode root) {
ArrayList<ArrayList<Integer>> lists = new ArrayList<>();
HashMap<TreeNode, Integer> map = new HashMap<>();
if (root == null) {
return lists;
}
Deque<TreeNode> queue = new ArrayDeque<>();
queue.addFirst(root);
map.put(root, 0);
while (!queue.isEmpty()) {
root = queue.pollLast();
int deep = map.get(root);
if (root.left != null) {
queue.addFirst(root.left);
map.put(root.left, deep + 1);
}
if (root.right != null) {
queue.addFirst(root.right);
map.put(root.right, deep + 1);
}
if (lists.size() <= deep) {
ArrayList<Integer> list = new ArrayList<>();
list.add(root.val);
lists.add(list);
} else {
ArrayList<Integer> list = lists.get(deep);
list.add(root.val);
}
}
return lists;
}

}
-------------本文结束感谢您的阅读-------------
0%