# 剑指offer编程题66道题 26-35

26.二叉搜索树与双向链表

## 题目描述

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

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

}

}
*/
public class Solution {
TreeNode pre = null;
public TreeNode Convert(TreeNode pRootOfTree) {
if(pRootOfTree == null) return pRootOfTree;

Convert(pRootOfTree.right);
if(pre == null){
pre = pRootOfTree;
} else {
pre.left = pRootOfTree;
pRootOfTree.right = pre;
pre = pRootOfTree;
}
Convert(pRootOfTree.left);

return pre;
}
}
View Code

1.采用左中右的中序遍历，遍历完之后头结点还得从右到左挪回来

2.更严重的问题是，我将pre设置为局部传递的变量，由于pre是引用的值传递，在递归回退的时候，pre的引用时上一次遍历pre的副本，而不是遍历后更改的值。解决方法就是讲pre设置为全局变量。

# 参考java的传值与传引用

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

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

}

}
*/
public class Solution {
public TreeNode Convert(TreeNode pRootOfTree) {
if(pRootOfTree == null)
return null;
TreeNode pre = null;
ConvertHelper(pRootOfTree,pre);
TreeNode res = pRootOfTree;
while(res.left != null){
res = res.left;
}
return res;
}

public void ConvertHelper(TreeNode cur, TreeNode pre){
if(cur == null)
return;
ConvertHelper(cur.left,pre);
cur.left = pre;
if(pre!=null) pre.right = cur;
pre = cur;
ConvertHelper(cur.right,pre);
}
}
View Code

链接：https://www.nowcoder.com/questionTerminal/947f6eb80d944a84850b0538bf0ec3a5

import java.util.Stack;
public class Solution {
public TreeNode Convert(TreeNode pRootOfTree) {
if(pRootOfTree == null) return pRootOfTree;

TreeNode list = null;
Stack<TreeNode> s = new Stack<>();
while(pRootOfTree != null || !s.isEmpty()){
if(pRootOfTree != null) {
s.push(pRootOfTree);
pRootOfTree = pRootOfTree.right;
} else {
pRootOfTree = s.pop();
if(list == null)
list = pRootOfTree;
else {
list.left = pRootOfTree;
pRootOfTree.right = list;
list = pRootOfTree;
}
pRootOfTree = pRootOfTree.left;
}
}

return list;
}
}
View Code

27.字符串的排列

## 题目描述

import java.util.ArrayList;
import java.util.Collections;
public class Solution {
public ArrayList<String> Permutation(String str) {
ArrayList<String> list = new ArrayList<String>();
if(str !=null && str.length() > 0){
PermutationHelper(str.toCharArray(),0,list);
Collections.sort(list);
}
return list;
}

public void  PermutationHelper(char[] cs, int i, ArrayList<String> list){
if(cs.length-1 == i){
String val = String.valueOf(cs);
if(!list.contains(val)){
}
}else{
for(int j=i; j<cs.length;j++){
swap(i,j,cs);
PermutationHelper(cs,i+1,list);
swap(i,j,cs);
}
}
}

public void swap(int i,int j,char[] cs){
char temp = cs[i];
cs[i] = cs[j];
cs[j] = temp;
}
}
View Code

最后一个循环是递归调用swap交换前后两个字符，在最后交换完成入List之后再交换回来，回到初始状态再进下一个循环

28.数组中出现次数超过一半的数字

## 题目描述

import java.util.*;
public class Solution {
public int MoreThanHalfNum_Solution(int [] array) {
Map<Integer,Integer> count = new HashMap<>();
if(array.length == 1)
return array[0];
for(int i:array){
if(!count.containsKey(i)){
count.put(i, 1);
}else{
count.put(i,count.get(i)+1);
if(count.get(i) > array.length/2)
return i;
}
}
return 0;
}
}
View Code

public class Solution {
public int MoreThanHalfNum_Solution(int [] array) {
if(array.length == 1)
return array[0];
int result = array[0];
int times = 0;
for(int i = 0;i<array.length; i++){
if(times == 0){
result = array[i];
times = 1;
}else if(result == array[i]){
times++;
}else{
times--;
}
}

times=0;
for(int i=0;i<array.length;i++){
if(result==array[i]){
times++;
}
}
if(times*2<=array.length){
result=0;
}
return result;

}
}
View Code

29.最小的K的个数

## 题目描述

1.偷懒解法（利用jdk自带的排序api）：
import java.util.*;
public class Solution {
public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
ArrayList<Integer> list = new ArrayList<>();
if(k>input.length)
return list;
Arrays.sort(input);
for(int i:Arrays.copyOfRange(input, 0, k)){
}
return list;
}
}
View Code

2.创建一个大小为k的数据容器，如果容器还没有有了k个数字，直接放入这个数到容器当中；如果容器中有了k个数字了，找出这已有的k个数字中的最大值，然后拿待插的数和最大值进行比较，小就替换，大就抛弃。如果用二叉树来实现这个容器，那么我们可以在O(logk)实现查找替换操作，对于n个输入数字而言，总的时间效率为O(nlogk)。

import java.util.ArrayList;
import java.util.PriorityQueue;
import java.util.Comparator;
public class Solution {
public ArrayList<Integer> GetLeastNumbers_Solution(int[] input, int k) {
ArrayList<Integer> result = new ArrayList<Integer>();
int length = input.length;
if(k > length || k == 0){
return result;
}
PriorityQueue<Integer> maxHeap = new PriorityQueue<Integer>(k, new Comparator<Integer>() {

@Override
public int compare(Integer o1, Integer o2) {
return o2.compareTo(o1);
}
});
for (int i = 0; i < length; i++) {
if (maxHeap.size() != k) {
maxHeap.offer(input[i]);
} else if (maxHeap.peek() > input[i]) {
Integer temp = maxHeap.poll();
temp = null;
maxHeap.offer(input[i]);
}
}
for (Integer integer : maxHeap) {
}
return result;
}
}
View Code

PriorityQueue<Integer> maxHeap = new PriorityQueue<Integer>(k, new Comparator<Integer>() {

@Override
public int compare(Integer o1, Integer o2) {
return o2.compareTo(o1);
}
});

3.冒泡法

链接：https://www.nowcoder.com/questionTerminal/6a296eb82cf844ca8539b57c23e6e9bf

public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
ArrayList<Integer> al = new ArrayList<Integer>();
if (k > input.length) {
return al;
}
for (int i = 0; i < k; i++) {
for (int j = 0; j < input.length - i - 1; j++) {
if (input[j] < input[j + 1]) {
int temp = input[j];
input[j] = input[j + 1];
input[j + 1] = temp;
}
}
}
return al;
}
View Code

30.连续子数组的最大和

HZ偶尔会拿些专业问题来忽悠那些非计算机专业的同学。今天测试组开完会后,他又发话了:在古老的一维模式识别中,常常需要计算连续子向量的最大和,当向量全为正数的时候,问题很好解决。但是,如果向量中包含负数,是否应该包含某个负数,并期望旁边的正数会弥补它呢？例如:{6,-3,-2,7,-15,1,2,2},连续子向量的最大和为8(从第0个开始,到第3个为止)。你会不会被他忽悠住？(子向量的长度至少是1)

1.两个循环遍历，时间复杂度为O（n2

public class Solution {
public int FindGreatestSumOfSubArray(int[] array) {
double max = -1.0/0.0;
for(int i = 0;i<array.length;i++){
double submax = -1.0/0.0;
int sum = 0;
for (int j=i;j<array.length;j++){
sum = sum + array[j];
if(sum > submax)
submax = sum;
}
if(submax>max)
max = submax;
}
return (int)max;
}
}
View Code
public class Solution {
public int FindGreatestSumOfSubArray(int[] array) {
int max = array[0];
for(int i = 0;i<array.length;i++){
int submax = array[i];
int sum = array[i];
for (int j=i+1;j<array.length;j++){
sum = sum + array[j];
if(sum > submax)
submax = sum;
}
if(submax>max)
max = submax;
}
return max;
}
}
View Code

2.采用动态规划法，时间复杂度为O（n）

public class Solution {
public int FindGreatestSumOfSubArray(int[] array) {
if(array.length == 0) return 0;
int sum = array[0];
int tempsum = array[0];
for(int i = 1;i<array.length;i++){
tempsum = (tempsum<0)?array[i]:tempsum + array[i];
sum = (tempsum > sum) ? tempsum : sum;
}
return sum;
}
}
View Code

31.1—n整数中1出现的次数

时间复杂度为O(nlogn)

public class Solution {
public int NumberOf1Between1AndN_Solution(int n) {
int number = 0;
for(int i=1;i<=n;i++){
number = number+numberOf1(i);
}
return number;
}

public int numberOf1(int i){
int number = 0;
while( i!= 0){
if(i % 10 ==1)
number++;
i = i/10;
}
return number;
}
}
View Code

时间复杂度为O（logn）

//主要思路：设定整数点（如1、10、100等等）作为位置点i（对应n的各位、十位、百位等等），分别对每个数位上有多少包含1的点进行分析
//根据设定的整数位置，对n进行分割，分为两部分，高位n/i，低位n%i
//当i表示百位，且百位对应的数>=2,如n=31456,i=100，则a=314,b=56，此时百位为1的次数有a/10+1=32（最高两位0~31），每一次都包含100个连续的点，即共有(a%10+1)*100个点的百位为1
//当i表示百位，且百位对应的数为1，如n=31156,i=100，则a=311,b=56，此时百位对应的就是1，则共有a%10(最高两位0-30)次是包含100个连续点，当最高两位为31（即a=311），本次只对应局部点00~56，共b+1次，所有点加起来共有（a%10*100）+(b+1)，这些点百位对应为1
//当i表示百位，且百位对应的数为0,如n=31056,i=100，则a=310,b=56，此时百位为1的次数有a/10=31（最高两位0~30）
//综合以上三种情况，当百位对应0或>=2时，有(a+8)/10次包含所有100个点，还有当百位为1(a%10==1)，需要增加局部点b+1
//之所以补8，是因为当百位为0，则a/10==(a+8)/10，当百位>=2，补8会产生进位位，效果等同于(a/10+1)
View Code
public class Solution {
public int NumberOf1Between1AndN_Solution(int n) {
int count=0;
int i=1;
for(i=1;i<=n;i*=10)
{
//i表示当前分析的是哪一个数位
int a = n/i,b = n%i;
if(a%10==1)
count=count+(a+8)/10*i+a%10*(b+1);
else
count=count+(a+8)/10*i;
}
return count;
}
}
View Code

32.把数组排成最小的数

## 题目描述

 * 解题思路：
 * 先将整型数组转换成String数组，然后将String数组排序，最后将排好序的字符串数组拼接出来。关键就是制定排序规则。
 * 排序规则如下：
 * 若ab > ba 则 a > b，
 * 若ab < ba 则 a < b，
 * 若ab = ba 则 a = b；
 * 解释说明：
 * 比如 "3" < "31"但是 "331" > "313"，所以要将二者拼接起来进行比较
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;

public class Solution {
public String PrintMinNumber(int [] numbers) {
/**
* 1.用list装numbers数组中的数
* 2.使用collection.sort进行排序，排序是将str1+""+str2和str2+""+str1的大小进行比较
* 3.将排序后的数组进行拼接
*/
if(numbers == null || numbers.length==0) return "";
ArrayList<Integer> list = new ArrayList<Integer>();
for(int i:numbers){
}
Collections.sort(list, new Comparator<Integer>(){
public int compare(Integer str1,Integer str2){
String s1 = str1 + "" + str2;
String s2 = str2 + "" + str1;
return s1.compareTo(s2);
}
});

StringBuffer sb= new StringBuffer();
for(int i:list)
sb.append(i);

return sb.toString();

}
}
View Code

33.丑数

## 题目描述

2*1  3*1  5*1
2*2  3*1  5*1
2*2  3*2  5*1
2*3  3*2  5*1
2*3  3*2  5*2
2*4  3*3  5*2
2*5  3*3  5*2
2*5  3*4  5*2
2*6  3*4  5*3
2*8  3*5  5*3
2*8  3*6  5*4
public class Solution {
public int GetUglyNumber_Solution(int index) {
if(index<7)
return index;
int[] ret = new int[index];
ret[0] =1;
int t2 = 0;int t3= 0; int t5=0;
for(int i=1;i<index;i++){
ret[i]=Math.min(Math.min(ret[t2]*2, ret[t3]*3), ret[t5]*5);
if(ret[i] == ret[t2]*2) t2++;
if(ret[i] == ret[t3]*3) t3++;
if(ret[i] == ret[t5]*5) t5++;
}
return   ret[index-1];
}

}
View Code

34.第一次只出现一次的字符

## 题目描述

import java.util.*;
public class Solution {
public int FirstNotRepeatingChar(String str) {
if(str == null || str.length() == 0)
return -1;
char[] strArray = str.toCharArray();
for(char a:strArray){
if(map.containsKey(a)){
map.put(a, map.get(a)+1);
}else
map.put(a, 1);
}

for(char key:map.keySet()){
if(map.get(key)==1)
return str.indexOf(key);
}
return -1;
}
}
View Code

35.数组中的逆序对

## 题目描述

public class Solution {
public int InversePairs(int [] array) {
if(array==null||array.length==0)
{
return 0;
}
int[] copy = new int[array.length];
for(int i=0;i<array.length;i++)
{
copy[i] = array[i];
}
int count = InversePairsCore(array,copy,0,array.length-1);//数值过大求余
return count;

}
private int InversePairsCore(int[] array,int[] copy,int low,int high)
{
if(low==high)
{
return 0;
}
int mid = (low+high)>>1;
int leftCount = InversePairsCore(array,copy,low,mid)%1000000007;
int rightCount = InversePairsCore(array,copy,mid+1,high)%1000000007;
int count = 0;
int i=mid;
int j=high;
int locCopy = high;
while(i>=low&&j>mid)
{
if(array[i]>array[j])
{
count += j-mid;
copy[locCopy--] = array[i--];
if(count>=1000000007)//数值过大求余
{
count%=1000000007;
}
}
else
{
copy[locCopy--] = array[j--];
}
}
for(;i>=low;i--)
{
copy[locCopy--]=array[i];
}
for(;j>mid;j--)
{
copy[locCopy--]=array[j];
}
for(int s=low;s<=high;s++)
{
array[s] = copy[s];
}
return (leftCount+rightCount+count)%1000000007;
}
}
View Code

没看懂。。。

posted @ 2018-06-08 21:49  开拖拉机的蜡笔小新  阅读(262)  评论(0编辑  收藏  举报