题目来自牛客网
输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。(注意:这两个序列的长度是相等的)
新建一个栈来验证即可
class Solution21{
public boolean IsPopOrder(int [] pushA,int [] popA) {
int len=pushA.length;
Stack stack=new Stack<>();
int i=0, j=0;
stack.push(pushA[j++]);
while(!(i==len&&j==len))
{
if(popA[i]==stack.peek())
{
stack.pop();
i++;
}
else if(j
从上往下打印出二叉树的每个节点,同层节点从左至右打印。
层次遍历,使用队列
class Solution22 {
public ArrayList PrintFromTopToBottom(TreeNode root) {
Queue queue = new LinkedList();
ArrayList list =new ArrayList<>();
if(root==null){//使用队列进行层次遍历
return list;
}
queue.offer(root);
while(!queue.isEmpty()){
TreeNode tr =queue.poll();
list.add(tr.val);
if(tr.left!=null){
queue.offer(tr.left);
}
if(tr.right!=null){
queue.offer(tr.right);
}
}
return list;
}
}
输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。
后序遍历序列的最后一个元素为二叉树的根节点;.二叉搜索树左子树上所有的结点均小于根结点、右子树所有的结点均大于根结点。
算法步骤如下:
class Solution23 {
public boolean VerifySquenceOfBST(int[] sequence) {
int len = sequence.length;
if (len == 0) {
return false;
}
if (len == 1) {
return true;
}
return IsPostOrder(sequence, 0, len - 1);
}
private boolean IsPostOrder(int[] s, int l1, int l2) {
if (l1 >= l2) {
return true;
}
int i = l1;
while (s[i] < s[l2]) {// 找到第一个大于根节点的节点
i++;
}
int j = i;
while (j < l2) {
if (s[j] < s[l2]) {
return false;
}
j++;
}
return IsPostOrder(s, l1, i - 1) && IsPostOrder(s, i, l2 - 1);
}
}
输入一颗二叉树的跟节点和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。(注意: 在返回值的list中,数组长度大的数组靠前)
正常遍历二叉树,访问一个节点就将其加入到list2中,向下遍历的时候target-root.val,反之则加并且移除该节点。若target==root.val并且没有左右子树时new一个List添加到list中。
class Solution24 {
ArrayList> list = new ArrayList>();
ArrayList list2 = new ArrayList();
public ArrayList> FindPath(TreeNode root,int target) {
if(root==null) {
return list;
}
list2.add(root.val);
if(root.val==target&&root.left==null&&root.right==null) {
list.add(new ArrayList(list2));
}
if(root.left!=null) {
FindPath(root.left, target-root.val);
}
if(root.right!=null) {
FindPath(root.right, target-root.val);
}
list2.remove(list2.size()-1);
target+=root.val;
return list;
}
}
输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点),返回结果为复制后复杂链表的head。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空)
1.将原链表复制一个节点添加到原来节点的后边,即原链表ABCD->AA’BB’CC’DD’
2.对复制后的链表添加随机连接
3.断链将新链表取出来
class RandomListNode {
int label;
RandomListNode next = null;
RandomListNode random = null;
RandomListNode(int label) {
this.label = label;
}
}
class Solution25 {
public RandomListNode Clone(RandomListNode pHead)
{
if(pHead==null) {
return null;
}
//第一步,复制
RandomListNode p =pHead;
while(p!=null) {
RandomListNode q = new RandomListNode(p.label);
q.next=p.next;
p.next=q;
p=q.next;
}
//第二步,连接
p =pHead;
while(p!=null) {
RandomListNode q=p.next;
if(p.random!=null) {
q.random=p.random.next;
}
p=q.next;
}
//第三步,断链
p =pHead;
RandomListNode head=p.next;
while(p!=null) {
RandomListNode q=p.next;
if(q.next!=null) {
p.next=q.next;
p=p.next;
q.next=p.next;
}
if(q.next==null) {
p.next=null;
p=p.next;
}
}
return head;
}
}
输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。
使用中序遍历,中序遍历的第一个不为空的节点为头结点,然后依次遍历连接即可
class Solution26 {
TreeNode head=null;TreeNode q=null;
public TreeNode Convert(TreeNode p) {
if(p==null) {
return null;
}
if(p.left!=null) {
Convert(p.left);
}
if(head==null) {//寻找头结点
head=p;
q=head;
}else {
p.left=q;
q.right=p;
q=p;
}
if(p.right!=null) {
Convert(p.right);
}
return head;
}
}
输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。
输入描述:
输入一个字符串,长度不超过9(可能有字符重复),字符只包括大小写字母。
递归操作,第一个数和后边的数交换,然后第二个数和后边的数交换,插入的时候查重,返回之前排序
推广:全排列问题可以借用此思路,逐一替换然后插入时判断
class Solution27 {
public ArrayList Permutation(String str) {
ArrayList list = new ArrayList();
if(str!=null) {
char[] a=str.toCharArray();
SortOfString(list,a,0);
Collections.sort(list);
}
return list;
}
private void SortOfString(ArrayList list, char[] a, int begin) {
if(begin==a.length-1) {
String s=new String(a);
if(!list.contains(s)) {
list.add(s);
}
return ;
}
for(int i =begin;i
数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。
记录第一个数为most,count为1,遍历数组遇到和most相等的数count+1,反之count-1。当count为0时,将most替换为当前元素,继续遍历,那么最后一个数则有可能是次数大于数组长度的一半的数,然后在遍历一次数组,确认是否正确
class Solution28 {
public int MoreThanHalfNum_Solution(int [] array) {
int most=array[0];
int count=1;
for(int i = 1;i< array.length;i++) {
if(array[i]==most) {
count++;
}else {
count--;
if(count<=0) {
most=array[i];
}
}
}
int num=0;
for(int i=0;iarray.length/2) {
return most;
}else {
return 0;
}
}
}
输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,。
1.堆排序 2.partition思想的快排
方法一:
class Solution29_1 {
public ArrayList GetLeastNumbers_Solution(int[] input, int k) {
ArrayList leastNumbers = new ArrayList();
while (input == null || k <= 0 || k > input.length)
return leastNumbers;
int[] numbers = new int[k]; // 用于放最小的k个数
for (int i = 0; i < k; i++)
numbers[i] = input[i];// 先放入前k个数
for (int i = k / 2 - 1; i >= 0; i--) {
adjustHeap(numbers, i, k - 1);// 将数组构造成最大堆形式
}
for (int i = k; i < input.length; i++) {
if (input[i] < numbers[0]) { // 存在更小的数字时
numbers[0] = input[i];
adjustHeap(numbers, 0, k - 1);// 重新调整最大堆
}
}
for (int n : numbers)
leastNumbers.add(n);
return leastNumbers;
}
// 最大堆的调整方法,
private void adjustHeap(int[] arr, int start, int end) {
int temp = arr[start];
int child = start * 2 + 1;
while (child <= end) {
if (child + 1 <= end && arr[child + 1] > arr[child])
child++;
if (arr[child] < temp)
break;
arr[start] = arr[child];
start = child;
child = child * 2 + 1;
}
arr[start] = temp;
}
}
方法二:
class Solution29_2 {
public ArrayList GetLeastNumbers_Solution(int[] input, int k) {
ArrayList aList = new ArrayList();
if (input.length == 0 || k > input.length || k <= 0)
return aList;
int low = 0;
int high = input.length - 1;
int index = Partition(input, k, low, high);
while (index != k - 1) {
if (index > k - 1) {
high = index - 1;
index = Partition(input, k, low, high);
} else {
low = index + 1;
index = Partition(input, k, low, high);
}
}
for (int i = 0; i < k; i++)
aList.add(input[i]);
return aList;
}
int Partition(int[] input, int k, int low, int high) {
int pivotkey = input[k - 1];
swap(input, k - 1, low);
while (low < high) {
while (low < high && input[high] >= pivotkey)
high--;
swap(input, low, high);
while (low < high && input[low] <= pivotkey)
low++;
swap(input, low, high);
}
return low;
}
private void swap(int[] input, int low, int high) {
int temp = input[high];
input[high] = input[low];
input[low] = temp;
}
}
HZ偶尔会拿些专业问题来忽悠那些非计算机专业的同学。今天测试组开完会后,他又发话了:在古老的一维模式识别中,常常需要计算连续子向量的最大和,当向量全为正数的时候,问题很好解决。但是,如果向量中包含负数,是否应该包含某个负数,并期望旁边的正数会弥补它呢?例如:{6,-3,-2,7,-15,1,2,2},连续子向量的最大和为8(从第0个开始,到第3个为止)。给一个数组,返回它的最大连续子序列的和,你会不会被他忽悠住?(子向量的长度至少是1)
两种解法:
1.直接法
sum记录当前和,maxsum记录最大和,当sum+当前值小于当前值的时候丢弃之前的和,从i开始记录
2.动态规划
方法一:
class Solution30_1 {
public int FindGreatestSumOfSubArray(int[] array) {
int sum=array[0];int maxsum=sum;
if(array==null||array.length==0) {
return 0;
}
if(array.length==1) {
return array[0];
}
for(int i=1;imaxsum) {
maxsum=sum;
}
}
return maxsum;
}
}
方法二:
class Solution30_2 {//DP
/**
动态规划
F(i):以array[i]为末尾元素的子数组的和的最大值,子数组的元素的相对位置不变
F(i)=max(F(i-1)+array[i] , array[i])
res:所有子数组的和的最大值
res=max(res,F(i))
*/
public int FindGreatestSumOfSubArray(int[] array) {
int max=array[0];
int res=array[0];
for(int i =1;i < array.length;i++ ) {
max=Math.max(max+array[i], array[i]);
res=Math.max(res, max);
}
return res;
}
}