原题链接:
第一题:复杂链表的复制
输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点),返回结果为复制后复杂链表的head。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空) 节点定义为: public class RandomListNode { RandomListNode(int label) { |
---|
分为三步: ①复制链表:nodea->nodea1->nodeb->nodeb1 ②复制链表的random指针 ③拆分链表 |
public class Solution {
public RandomListNode Clone(RandomListNode pHead){
if(pHead==null)return null;
RandomListNode pcur=pHead;
//第一步
while(pcur!=null){
RandomListNode node = new RandomListNode(pcur.label);
node.next=pcur.next;//先把当前节点的下一个节点给复制节点的下一个
pcur.next=node;//当前节点的下一个是node
pcur=node.next;//当前节点指向复制节点的下一个
}
//第二步
pcur=pHead;
while(pcur!=null){
if(pcur.random!=null){
RandomListNode random=pcur.random;
pcur.next.random=random.next;
}
pcur=pcur.next.next;
}
//第三步
RandomListNode head=pHead.next;
RandomListNode cur=head;
pcur=pHead;
while(pcur!=null){
pcur.next=pcur.next.next;
if(cur.next!=null)
cur.next=cur.next.next;
cur=cur.next;
pcur=pcur.next;
}
return head;
}
}
第二题:二叉树和双向链表
输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。 |
---|
解法一:递归遍历,类似中序遍历 将二叉树的左节点转换为双向链表的前指针,右节点转换为后指针 先遍历左子树,然后把根连在左子树后面,最后把右子树遍历完加在根的后面
|
public class Solution {
TreeNode pre=null;
TreeNode head=null;
public TreeNode Convert(TreeNode pRootOfTree) {
if(pRootOfTree==null)return null;
Convert( pRootOfTree.left);
if(pre==null){
pre=pRootOfTree;
head=pRootOfTree;
}else{
pre.right=pRootOfTree;
pRootOfTree.left=pre;
pre=pRootOfTree;
}
Convert( pRootOfTree.right);
return head;
}
}
方法二:类似于非递归的中序遍历 根据递归,建立栈结构,找到最左的节点,修改当前遍历节点与前一遍历节点的指针指向
|
public class Solution {
public TreeNode Convert(TreeNode pRootOfTree) {
if(pRootOfTree==null)return null;
Stack stack=new Stack();
TreeNode pre=null;
TreeNode pcur=pRootOfTree;
boolean isFirst=true;
while(!(pcur==null && stack.isEmpty())){
//找到最左的节点
while(pcur!=null){
stack.push(pcur);
pcur=pcur.left;
}
//对当前节点设置
pcur=stack.pop();
if(isFirst){
pRootOfTree=pcur;//将最左的节点计为链表的头节点返回
pre=pRootOfTree;
isFirst=false;
}else{
pre.right=pcur;
pcur.left=pre;
pre=pcur;
}
//遍历右节点
pcur=pcur.right;
}
return pRootOfTree;
}
}
第三题:字符串的排列
输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4 |
---|
递归: eg: [abc] / | \ a[bc] b[ac] c[ba] 第一个a和后面的每个单词交换,得到的新的字符串递归到后俩个单词(每次交换完,递归后要换来) / \ / \ / \ abc acb bac bca cba cab
|
import java.util.ArrayList;
import java.util.Collections;
public class Solution {
public ArrayList Permutation(String str) {
ArrayList res=new ArrayList ();
if(str==null)return res;
char[] chs=str.toCharArray();
Permutation(chs,res,0);
Collections.sort(res);
return res;
}
public void Permutation(char [] chs,ArrayList list,int index){
if(chs.length==0||chs==null)return;
if(index==chs.length){
String str=String.valueOf(chs);
if(list.contains(str))return ;
else list.add(str);
}else{
for(int i=index;i
第四题:数组中出现次数超过一半的数字
数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。 |
---|
第一个数字作为第一个士兵,守阵地;temp = 1; |
public class Solution {
public int MoreThanHalfNum_Solution(int [] array) {
if(array==null||array.length==0)return 0;
int temp=1;
int r=array[0];
for(int i=1;i array.length/2) ? r: 0;
}
}
第五题:最小的K个数
输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。 |
---|
方法一: 定义一个list集合,集合里先存数组的前k个数据,然后后面的数据和和集合里最大的数据进行比较,如果当前数据比list最大的数据小,更新list集合 |
import java.util.ArrayList;
public class Solution {
public ArrayList GetLeastNumbers_Solution(int [] input, int k) {
ArrayList list = new ArrayList();
if(input.length < k || k == 0)
return list;
for (int i = 0; i < k; i++)
list.add(input[i]);
for (int i = k; i < input.length; i++) {
int j = this.getMax(list);
int temp = (Integer) list.get(j);
if (input[i] < temp)
list.set(j, input[i]);
}
return list;
}
public int getMax(ArrayList list) {
int max = list.get(0);
int j = 0;
for (int i = 1; i < list.size(); i++) {
if (list.get(i) > max) {
max = list.get(i);
j = i;
}
}
return j;
}
}
方法二: 基于Partation快速排序: 如果Partation得到的结果是k-1,说明k前面有k个最小的,直接返回 如果结果小于k-1,递归到Partation得到的结果后面(要得到k个小的数,pivot肯定在结果后面) 否则,递归到递归到Partation得到的结果前面(要得到k个小的数,pivot肯定在结果前面) Partation中选择的pivot是开始位置的数据 |
import java.util.*;
public class Solution {
public ArrayList GetLeastNumbers_Solution(int [] input, int k) {
ArrayList list = new ArrayList();
if(input.length=pivot)end--;
a[begin]=a[end];
while(begin
用最大堆保存这k个数,每次只和堆顶比,如果比堆顶小,删除堆顶,新数入堆
|
import java.util.ArrayList;
import java.util.PriorityQueue;
import java.util.Comparator;
public class Solution {
public ArrayList GetLeastNumbers_Solution(int[] input, int k) {
ArrayList result = new ArrayList();
int length = input.length;
if(k > length || k == 0){
return result;
}
//用优先队列建立大根堆,堆顶元素为最大元素
PriorityQueue maxHeap = new PriorityQueue(k, new Comparator() {
@Override
public int compare(Integer o1, Integer o2) {
return o2.compareTo(o1);
}
});
for (int i = 0; i < length; i++) {
if (maxHeap.size() input[i]) {//堆顶大于当前数据,堆顶元素替换为当前元素
maxHeap.poll();
maxHeap.offer(input[i]);
}
}
for (Integer integer : maxHeap) {
result.add(integer);
}
return result;
}
}
六题:连续子数组的最大和
HZ偶尔会拿些专业问题来忽悠那些非计算机专业的同学。今天测试组开完会后,他又发话了:在古老的一维模式识别中,常常需要计算连续子向量的最大和,当向量全为正数的时候,问题很好解决。但是,如果向量中包含负数,是否应该包含某个负数,并期望旁边的正数会弥补它呢?例如:{6,-3,-2,7,-15,1,2,2},连续子向量的最大和为8(从第0个开始,到第3个为止)。给一个数组,返回它的最大连续子序列的和,你会不会被他忽悠住?(子向量的长度至少是1) |
---|
定义sum和max,max记录最大值 sum记录子串和,如果sum<0,记录sum从当前位置开始,否则,把当前的数据加到sum中 每次将max和sum进行比较,持续更新max的值
|
public class Solution {
public int FindGreatestSumOfSubArray(int[] array) {
if(array==null||array.length==0)return 0;
int sum=0,max=Integer.MIN_VALUE;
for(int i=0;imax)
max=sum;
}
return max;
}
}