剑指Offer行榜【牛客网】练习(六)

28 篇文章 0 订阅
13 篇文章 0 订阅
1、二叉搜索树与双向链表

题目描述:
输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。

思路:
二叉搜索树要转成排序的双向链表=中序列表+修改链接。既可以把这两步分开,也可以合起来一起(参照博客见文末)。

代码:

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

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

    }

}
*/
import java.util.ArrayList;
//将中序和重新链接分开的代码如下:
public class Solution {
    static ArrayList<TreeNode> list = new ArrayList<>();
    public TreeNode Convert(TreeNode pRootOfTree) {
        if(pRootOfTree==null){
            return null;
        }
        list = new ArrayList<>();
        saveAsList(pRootOfTree);
        if(list.size()==1){
            return list.get(0);
        }
        list.get(0).right = list.get(1);
        for(int i=1;i<list.size()-1;i++){
            list.get(i).right = list.get(i+1);
            list.get(i).left = list.get(i-1);
        }
        list.get(list.size()-1).left = list.get(list.size()-2);
        return list.get(0);
    }
    public static void saveAsList(TreeNode pRootOfTree){
        if(pRootOfTree==null){
            return;
        }
        if(pRootOfTree.left!=null){
            saveAsList(pRootOfTree.left);
        }
        list.add(pRootOfTree);
        if(pRootOfTree.right!=null){
            saveAsList(pRootOfTree.right);
        }
    }
}
//将中序和链接结合的代码如下:
public class Solution {
    public static TreeNode Convert(TreeNode pRootOfTree) {
			TreeNode lastNode =null;//上一个结点
			TreeNode headNode=ConvertNode(pRootOfTree, lastNode);
			//找开头结点
			while (headNode != null && headNode.left != null) {
				headNode = headNode.left;
			}
			return headNode;
		}
 
		public static TreeNode ConvertNode(TreeNode rootTree, TreeNode lastNode) {
			if (rootTree == null) {
				return null;
			}
			if (rootTree.left != null) {
			//中序遍历,有左先向左找
				lastNode=ConvertNode(rootTree.left, lastNode);
			}
			//修改链接顺序
			rootTree.left = lastNode;
			if (lastNode != null) {
				lastNode.right = rootTree;
			}
			//修改上一个结点为当前结点
			lastNode = rootTree;
			if (rootTree.right != null) {
			//中序遍历,有右向右找
				lastNode=ConvertNode(rootTree.right, lastNode);
			}
			return lastNode;
		}
 
}

2、字符串的排列

题目描述:
输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。

思路:
解法一、先找出所有排列,然后消除相同String,最后排序
解法二、在排列过程中消除相同String,参照博客见文末

代码:

//解法一
import java.util.ArrayList;
import java.util.Collections;
public class Solution {
    public ArrayList<String> Permutation(String str) {
        ArrayList<String> result = new ArrayList<String>();
        if(str.length()==0){
            return result;
        }
        char[] c = str.toCharArray();
        getAllOrder(c,0,c.length-1,result);
        ArrayList<String> noSame = new ArrayList<>();
        for(int i=0;i<result.size();i++){
            if(notExist(result.get(i),noSame)){
                noSame.add(result.get(i));
            }
        }
        Collections.sort(noSame);
        return noSame;
    }
    public static boolean notExist(String s,ArrayList<String> list){
        boolean result = true;
        for(int i=0;i<list.size();i++){
            if(list.get(i).equals(s)){
                result = false;
                break;
            }
        }
        return result;
    }
    public static void getAllOrder(char[] c, int s, int e, ArrayList<String> result){
        if(s>e){
            String str = "";
            for(int i=0;i<c.length;i++){
                str+=c[i];
            }
            result.add(str);
            return;
        }else{
            for(int i=s;i<=e;i++){
                swap(c,s,i);
                getAllOrder(c,s+1,e,result);
                swap(c,s,i);
            }
        }
    }
    public static void swap(char[] c,int x, int y){
        char temp = c[x];
        c[x] = c[y];
        c[y] = temp;
    }
    
}
//解法二
import java.util.ArrayList;
import java.util.Collections;
public class Solution {
    public ArrayList<String> Permutation(String str) {
        ArrayList<String> result = new ArrayList<String>();
        if(str.length()==0){
            return result;
        }
        char[] c = str.toCharArray();
        getAllOrder(result,c,0,c.length);
        return result;
    }
    
    public static void getAllOrder(ArrayList<String> result, char[] c, int index, int len){
        char[] cp = new char[c.length];
        for(int i=0;i<c.length;i++){
            cp[i] = c[i];
        }
        if(index==len){
            String str = "";
            for(int i=0;i<cp.length;i++){
                str+=cp[i];
            }
            result.add(str);
            return;
        }else{
            for(int i=index;i<len;i++){
            	//消除重复
                if(i!=index&&cp[i]==cp[index]) continue;
                swap(cp,index,i);
                getAllOrder(result,cp,index+1,cp.length);
            }
        }
    }
    public static void swap(char[] c,int x, int y){
        char temp = c[x];
        c[x] = c[y];
        c[y] = temp;
    }
}
3、数组中出现次数超过一半的数字

题目描述:
数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。

思路:
使用map保存每一个数字的个数即可。

代码:

import java.util.HashMap;
public class Solution {
    public int MoreThanHalfNum_Solution(int [] array) {
        int len = 0;
        if(array.length%2==0){
            len = array.length/2;
        }else{
            len = array.length/2;
        }
        HashMap<Integer,Integer> map = new HashMap<>();
        for(int i=0;i<array.length;i++){
            if(map.containsKey(array[i])){
                int value = map.get(array[i])+1;
                map.put(array[i],value);
            }else{
                map.put(array[i],1);
            }
        }
        for(Integer i: map.keySet()){
            if(map.get(i)>len){
                return (int)i;
            }
        }
        return 0;
    }
}
4、最小的K个数

题目描述:
输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4。

思路:
排序算法。冒泡,快排或者Collections.sort都行。

代码:

import java.util.Arrays;
import java.util.Collections;
import java.util.ArrayList;
public class Solution {
    public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
        if(k>input.length){
            return new ArrayList<>();
        }
        ArrayList<Integer> num = new ArrayList<>();
        for(int i=0;i<input.length;i++){
            num.add(input[i]);
        }
        Collections.sort(num);
        ArrayList<Integer> result = new ArrayList<>();
        for(int i=0;i<k;i++){
            result.add(num.get(i));
        }
        return result;
    }
}
5、连续子数组最大和

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

思路:
思想是动态规划。到第i个数的时候,可以保存
1、每一步所得和的最大值
2、取得所得和的最大值的index
若前一步的值+自身>=自身&&前一步的index与自身的index相连,则选择连续。
若前一步的值+自身<自身&&前一步的index与自身的index相连,分两种情况:

  • 若前一步的值>自身,选择前一步的值,且修改index为前一步的index
  • 若前一步的值<=自身,选择自身的值

若前一步的index与自身的index不相连,比较从开头到自身的和与自身的值。

代码:

public class Solution {
    public int FindGreatestSumOfSubArray(int[] array) {
        int[] index = new int[array.length];
        int[] sum = new int[array.length];
        for(int i=0;i<index.length;i++){
            index[i] = i;
        }
        sum[0] = array[0];
        int maxsum = Integer.MIN_VALUE;
        for(int i=1;i<array.length;i++){
            if(sum[i-1]+array[i]>=array[i]&&index[i-1]+1==index[i]){
                sum[i] = sum[i-1]+array[i];
            }
            else if(sum[i-1]+array[i]<array[i]&&index[i-1]+1==index[i]){
                if(array[i]<sum[i-1]){
                    sum[i] = sum[i-1];
                    index[i] = index[i-1];
                }else{
                    sum[i] = array[i];
                }
            }
            else if(index[i-1]+1!=index[i]){
                int sumi = 0;
                for(int j=0;j<=i;j++){
                    sumi+=array[j];
                }
                if(sumi>=array[i]){
                    sum[i] = sumi;
                }else{
                    sum[i] = array[i];
                }
            }
            maxsum = Math.max(maxsum,sum[i]);
        }
        return maxsum;
    }
}

题1的中序和链接结合解法参照 https://blog.csdn.net/qq_23217629/article/details/51751176
题2的第二种解法参照 https://blog.csdn.net/u013113231/article/details/56872992

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值