剑指offer有java版么_剑指offer-Java版(上)

1.二维数组中的查找

在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。

思路

类似于二分查找,根据题目,如果拿数组中任意一个元素与目标数值进行比较,如果该元素小于目标数值,那么目标数值一定是在该元素的下方或右方,如果大于目标数值,那么目标数值一定在该元素的上方或者左方。 在二维数组的查找中,两个指针是一个上下方向移动,一个是左右方向移动。两个指针可以从同一个角出发。本题从右上角出发寻找解题思路。

代码

public class Solution {

public boolean Find(int target, int [][] array) {

int row = 0;

int col = array[0].length -1;

while(row < array.length && col >= 0){

if(array[row][col]>target)

col -= 1;

else if(array[row][col]

row += 1;

else

return true;

}

return false;

}

}

2.替换空格

请实现一个函数,将一个字符串中的每个空格替换成“%20”。例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。

代码

public class Solution {

public String replaceSpace(StringBuffer str) {

StringBuffer res = new StringBuffer();

int len = str.length() -1;

for(int i=0; i<=len; i++){

if(str.charAt(i) == ' ')

res.append("%20");

else

res.append(str.charAt(i));

}

return res.toString();

}

}

//charAt()方法用于返回指定索引处的字符

3.从尾到头打印链表

输入一个链表,按链表值从尾到头的顺序返回一个ArrayList。

思路:使用栈从头到尾push链表的元素,然后pop所有的元素到一个list中并返回。

代码

/*** public class ListNode {* int val;* ListNode next = null;* ListNode(int val) {* this.val = val;* }* }*/

import java.util.ArrayList;

public class Solution {

public ArrayList printListFromTailToHead(ListNode listNode) {

ArrayList arr = new ArrayList();

ListNode p = listNode;

ArrayList stack = new ArrayList();

while(p!=null){

stack.add(p.val);

p = p.next;

}

int n = stack.size()-1;

for(int i=n;i>=0;i--){

arr.add(stack.get(i));

}

return arr;

}

}

4.重建二叉树

输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。

思路:先序遍历和中序遍历的关系,先序遍历的第一个值是根节点的值。在中序遍历中,根节点左边的值是左子树,右边的值是右子树上的值。

代码

/*** Definition for binary tree* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode(int x) { val = x; }* }*/

public class Solution {

public TreeNode reConstructBinaryTree(int [] pre,int [] in) {

if(pre.length == 0 || in.length == 0)

return null;

return buildTree(pre, in, 0, pre.length - 1, 0, in.length - 1);

}

public TreeNode buildTree(int[] pre, int[] in, int preStart, int preEnd, int inStart, int inEnd){

TreeNode root = new TreeNode(pre[preStart]);

int i = 0;

for(; i < in.length; i++){

if(in[i] == root.val)

break;

}

int leftLength = i - inStart;

int rightLength = inEnd - i;

if(leftLength > 0)

root.left = buildTree(pre, in, preStart+1, preStart+leftLength, inStart, i-1);

if(rightLength > 0)

root.right = buildTree(pre, in, preStart+leftLength+1, preEnd, i+1, inEnd);

return root;

}

}

5.用两个栈实现一个队列

用两个栈来实现一个队列,完成队列的Push和Pop操作。 队列中的元素为int类型。

思路

定义两个stack,分别是stack1和stack2,队列的push和pop是在两侧的,push操作很简单,只需要在stack1上操作,而pop操作时,先将stack1的所有元素push到stack2中,然后stack2的pop返回的元素即为目标元素,然后把stack2中的所有元素再push到stack1中。

代码

import java.util.Stack;

public class Solution {

Stack stack1 = new Stack();

Stack stack2 = new Stack();

public void push(int node) {

stack1.push(node);

}

public int pop() {

int temp;

while(!stack1.empty()){

temp = stack1.pop();

stack2.push(temp);

}

int res = stack2.pop();

while(!stack2.empty()){

temp = stack2.pop();

stack1.push(temp);

}

return res;

}

}

6.旋转数组中的最小数字

把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。 输入一个非减排序的数组的一个旋转,输出旋转数组的最小元素。 例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。 NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。

思路:这个题很简单,题目说的不明白,意思是一个递增排序的数组做了一次旋转,给你旋转后的数组,找到最小元素。输入{3,4,5,1,2}输出1。

两个方法:1.遍历数组元素,如果前一个元素大于后一个元素,则找到了最小的元素。如果前一个一直小于后一个元素,说明没有旋转,返回第一个元素。

2.二分查找,如果中间元素位于递增元素,那么中间元素>最右边元素,最小元素在后半部分。否则,最小元素在前半部分。

代码

1.时间复杂度O(n)

import java.util.ArrayList;

public class Solution {

public int minNumberInRotateArray(int [] array) {

if(array.length==0)

return 0;

for(int i=0;i

if(array[i] > array[i+1])

return array[i+1];

}

return array[0];

}

}

2.二分查找时间复杂度O(logn)

import java.util.ArrayList;

public class Solution {

public int minNumberInRotateArray(int [] array) {

if(array.length==0)

return 0;

int l=0;

int r=array.length-1;

while(l

int mid=(l+r)/2;

if(array[mid]>array[r])

l = mid+1;

else

r = mid;

}

return array[l];

}

}

7.斐波那契数列

要求输入一个整数n,请你输出斐波那契数列的第n项(从0开始,第0项为0),n<=39。

思路:菲波那切数列:F(1)=1,F(2)=1, F(n)=F(n-1)+F(n-2)(n>=3,n∈N*)

只需定义两个整型变量,b表示后面的一个数字,a表示前面的数字即可。每次进行的变换是:temp = a,a=b,b=temp + b

代码

public class Solution {

public int Fibonacci(int n) {

if(n<=0)

return 0;

int a=1, b=1;

int temp;

for(int i=2;i

temp = a;

a = b;

b = temp+b;

}

return b;

}

}

8.跳台阶

一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果)。

思路:典型的动态规划问题,对于第n阶台阶来说,有两种办法,一种是爬一个台阶,到第n-1阶;第二种是爬两个台阶,到第n-2阶。

得出动态规划递推式:

equation?tex=F%28n%29%3DF%28n-1%29%2BF%28n-2%29

代码

public class Solution {

public int JumpFloor(int target) {

if(target<=0)

return 0;

if(target == 1)

return 1;

int a=1,b=2;

int temp;

for(int i=3;i<=target;i++){

temp = a;

a = b;

b = temp+b;

}

return b;

}

}

9.变态跳台阶

一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。

思路:n=0时,f(n)=0;n=1时,f(n)=1;n=2时,f(n)=2;假设到了n级台阶,我们可以n-1级一步跳上来,也可以不经过n-1级跳上来,所以f(n)=2*f(n-1)。

推公式也能得出:

n = n时:f(n) = f(n-1)+f(n-2)+...+f(n-(n-1)) + f(n-n) = f(0) + f(1) + f(2) + ... + f(n-1)

由于f(n-1) = f(0)+f(1)+f(2)+ ... + f((n-1)-1) = f(0) + f(1) + f(2) + f(3) + ... + f(n-2)

所以f(n) = f(n-1)+f(n-1)=2*f(n-1)

代码

public class Solution {

public int JumpFloorII(int target) {

if(target<=0)

return 0;

if (target == 1) return 1;

if (target == 2) return 2;

int[] result=new int[target];

result[0]=1;

result[1]=2;

for(int i=2;i

result[i]=2*result[i-1];

}

return result[target-1];

}

}

10.矩阵覆盖

我们可以用2*1的小矩形横着或者竖着去覆盖更大的矩形。请问用n个2*1的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法?

思路:n = 1: f(n) = 1; n=2 : f(n) = 2;

假设到了n,那么上一步就有两种情况,在n-1的时候,竖放一个矩形,或着是在n-2时,横放两个矩形(这里不能竖放两个矩形,因为放一个就变成了n-1,那样情况就重复了),所以总数是f(n)=f(n-1)+f(n-2)。时间复杂度O(n)。和跳台阶题一样。

代码

public class Solution {

public int RectCover(int target) {

if(target<=0)

return 0;

if(target==1)

return 1;

if(target==2)

return 2;

int[] res=new int[target];

res[0]=1;

res[1]=2;

for(int i=2;i<=target-1;i++){

res[i]=res[i-1]+res[i-2];

}

return res[target-1];

}

}

11.二进制中1的个数

输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。例如,9表示1001,因此输入9,输出2。

思路:如果整数不等于0,那么该整数的二进制表示中至少有1位是1。

先假设这个数的最右边一位是1,那么该数减去1后,最右边一位变成了0,其他位不变。

再假设最后一位不是1而是0,而最右边的1在第m位,那么该数减去1,第m位变成0,m右边的位变成1,m之前的位不变。

上面两种情况总结,一个整数减去1,都是把最右边的1变成0,如果它后面还有0,那么0变成1。那么我们把一个整数减去1,与该整数做位运算,相当于把最右边的1变成了0,比如1100与1011做位与运算,得到1000。那么一个整数中有多少个1就可以做多少次这样的运算。

代码

public class Solution {

public int NumberOf1(int n) {

int count=0;

while(n!=0){

count +=1;

n = (n-1)&n;

}

return count;

}

}

12.数值的整数次方

给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。

代码:考虑base=0/exponent=0/exponent<0的情况 。

public class Solution {

public double Power(double base, int exponent) {

if(exponent==0)

return 1;

if(base==0)

return 0;

int flag=1;

double res=1;

if(exponent<0){

flag =-1;

exponent = -exponent;

}

while(exponent!=0){

res = res*base;

exponent -= 1;

}

if(flag==-1){

res = 1/res;

}

return res;

}

}

13.调整数组顺序使奇数位于偶数前面

输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。

import java.util.ArrayList;

import java.util.List;

public class Solution {

public void reOrderArray(int [] array) {

List arr1=new ArrayList();

List arr2 = new ArrayList();

for(int i=0;i

if(array[i]%2!=0)

arr1.add(array[i]);

else

arr2.add(array[i]);

}

List list =new ArrayList();

list.addAll(arr1);

list.addAll(arr2);

for(int i=0;i

array[i]=(Integer)list.get(i);

}

}

}

14.链表中的倒数第K个节点

输入一个链表,输出该链表中倒数第k个结点。

思路:假设链表中的节点数大于等于k个,那么一定会存在倒数第k个节点,首先使用一个快指针先往前走k步,然后两个指针每次走一步,两个指针之间始终有k的距离,当快指针走到末尾时,慢指针所在的位置就是倒数第k个节点。

代码

public class Solution {

public ListNode FindKthToTail(ListNode head,int k) {

if(head == null)

return null;

ListNode fast = head;

ListNode slow = head;

int t=0;

while(fast!=null && t

t += 1;

fast = fast.next;

}

if(t

return null; //考虑链表的长度

fast = fast.next;

slow = slow.next;

}

return slow;

}

}

15.反转链表

public class Solution {

public ListNode ReverseList(ListNode head) {

if(head==null)

return null;

ListNode p = head;

ListNode q = head.next;

while(q!=null){

head.next = q.next;

q.next = p;

p = q;

q = head.next;

}

return p;

}

}

16.合并两个排序的链表

输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。

public class Solution {

public ListNode Merge(ListNode list1,ListNode list2) {

if(list1==null)

return list2;

if(list2==null)

return list1;

ListNode head = new ListNode(-1);

ListNode list3 = head;

while(list1 != null && list2 != null){

if(list1.val <= list2.val){

head.next = list1;

list1 = list1.next;

}

else{

head.next = list2;

list2 = list2.next;

}

head = head.next;

}

while(list1 != null){

head.next = list1;

list1=list1.next;

head = head.next;

}

while(list2 != null){

head.next = list2;

list2=list2.next;

head = head.next;

}

return list3.next;

}

}

17.树的子结构

输入两棵二叉树A,B,判断B是不是A的子结构。(空树不是任意一个树的子结构)

思路:采用递归的思路,单独定义一个函数判断B是不是从当前A的根节点开始的子树,这里判断是不是子树也需要一个递归的判断。如果是,则返回True,如果不是,再判断B是不是从当前A的根节点的左子节点或右子节点开始的子树。

public class Solution {

public boolean HasSubtree(TreeNode root1,TreeNode root2) {

if(root1==null || root2==null)

return false;

boolean result = false;

if(root1.val==root2.val)

result = isSubtree(root1,root2);

if(!result)

result = HasSubtree(root1.left,root2);

if(!result)

result = HasSubtree(root1.right,root2);

return result;

}

public boolean isSubtree(TreeNode root1,TreeNode root2){

if(root2==null)

return true;

if(root1==null)

return false;

if(root1.val != root2.val)

return false;

return isSubtree(root1.left,root2.left) && isSubtree(root1.right,root2.right);

}

}

18.二叉树的镜像

操作给定的二叉树,将其变换为源二叉树的镜像。

二叉树的镜像定义:源二叉树 镜像二叉树

8 8

/ \ / \

6 10 10 6

/ \ / \ / \ / \

5 7 9 11 11 9 7 5

代码:递归交换左右结点

public class Solution {

public void Mirror(TreeNode root) {

if(root == null)

return ;

TreeNode temp;

temp = root.left;

root.left = root.right;

root.right = temp;

Mirror(root.left);

Mirror(root.right);

}

}

19.顺时针打印矩阵

输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下4 X 4矩阵: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 则依次打印出数字1,2,3,4,8,12,16,15,14,13,9,5,6,7,11,10.

思路:输出第一行后逆时针翻转矩阵。

代码

import java.util.ArrayList;

public class Solution {

ArrayList arr = new ArrayList();

public ArrayList printMatrix(int [][] matrix) {

if(matrix.length == 0)

return arr;

int rows = matrix.length;

int cols = matrix[0].length;

int start = 0;

while(rows > start * 2 && cols > start * 2){

printOneCircle(matrix,start,rows,cols);

start += 1;

}

return arr;

}

public void printOneCircle(int[][] matrix,int start,int rows,int cols){

int endrow = rows - start - 1;

int endcol = cols - start - 1;

for(int i=start;i<=endcol;i++){

arr.add(matrix[start][i]);

}

if(endrow > start)

for(int i = start+1;i<=endrow;i++){

arr.add(matrix[i][endcol]);

}

if(endrow > start && endcol > start)

for(int i=endcol - 1;i>=start;i--){

arr.add(matrix[endrow][i]);

}

if(endrow > start + 1 && endcol > start)

for(int i = endrow - 1;i>start;i--){

arr.add(matrix[i][start]);

}

}

}

20.包含min函数的栈

定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的min函数(时间复杂度应为O(1))。

import java.util.Stack;

public class Solution {

Stack stack = new Stack();

Stack minstack = new Stack();

public void push(int node) {

stack.push(node);

if(minStack.empty() || node < minStack.peek())

minStack.push(node);

else

minStack.push(minStack.peek());

}

public void pop() {

if(!stack.empty()){

stack.pop();

minStack.pop();

}

}

public int top() {

if(!stack.empty()){

return stack.peek(); //peek()返回栈顶元素但不弹出 }

else

return -1;

}

public int min() {

if(!minStack.empty())

return minStack.peek();

else

return -1;

}

}

21.栈的压入、弹出

输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。(注意:这两个序列的长度是相等的)

思路:栈的压入顺序是指1,2,3,4,5是依次push到栈的,但并不是说只有push的过程,也可能有pop的操作,比如push 1,2,3,4之后,把4pop出去,然后再push5,再pop5,然后依次pop3,2,1。弹出序列是指每次pop出去的元素都是当时栈顶的元素。

那么就可以构造一个辅助栈来判断弹出序列是不是和压栈序列对应。首先遍历压栈序列的元素push到辅助栈,判断是不是弹出序列的首元素,如果是,则弹出序列pop首元素(指针后移),如果不是,则继续push,再接着判断;直到遍历完了压栈序列,如果辅助栈或者弹出序列为空,则返回True,否则返回False

代码

import java.util.ArrayList;

import java.util.Stack;

public class Solution {

public boolean IsPopOrder(int [] pushA,int [] popA) {

Stack stack = new Stack();

int index = 0;

for(int i=0;i

if(pushA[i]==popA[index]){

index += 1;

}

else

stack.push(pushA[i]);

}

while(index

if(popA[index] != stack.pop())

return false;

index +=1;

}

return true;

}

}

22.从上到下打印二叉树

从上往下打印出二叉树的每个节点,同层节点从左至右打印。

//二叉树的层次遍历import java.util.*;

public class Solution {

public ArrayList PrintFromTopToBottom(TreeNode root) {

ArrayList list = new ArrayList();

Deque deque = new LinkedList();

if(root==null)

return list;

deque.add(root);

while(!deque.isEmpty()){

TreeNode t = deque.pop();

list.add(t.val);

if(t.left != null)

deque.add(t.left);

if(t.right != null)

deque.add(t.right);

}

return list;

}

}

23.二叉搜索树的后序遍历序列

输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。

思路:递归判断。如果序列的长度小于2,那一定是后序遍历的结果。根据BST和后序遍历的性质,遍历结果的最后一个一定是根节点,那么序列中前面一部分小于根节点的数是左子树,后一部分是右子树,递归进行判断。

代码

public class Solution {

public boolean VerifySquenceOfBST(int[] sequence) {

if(sequence.length==0)

return false;

return isSequenceOfBST(sequence,0,sequence.length-1);

}

public boolean isSequenceOfBST(int[] sequence,int start,int end){

if(end-start <2)

return true;

int flag = sequence[end];

int i=start;

while(sequence[i]

i+=1;

for(int j=i;j

if(sequence[j]

return false;

}

return isSequenceOfBST(sequence,start,i-1) && isSequenceOfBST(sequence,i,end-1);

}

}

24.二叉树中和为某一值的路径

输入一颗二叉树的根节点和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。(注意: 在返回值的list中,数组长度大的数组靠前)

思路:定义一个子函数,输入的是当前的根节点、当前的路径以及还需要满足的数值,同时在子函数中运用回溯的方法进行判断。

代码

import java.util.ArrayList;

public class Solution {

public ArrayList> res = new ArrayList<>();

public ArrayList> FindPath(TreeNode root,int target) {

if(root==null)

return res;

ArrayList arr = new ArrayList();

subPath(root,arr,target);

return res;

}

public void subPath(TreeNode node,ArrayList arr,int target){

if(node.left==null && node.right==null && target==node.val){

arr.add(node.val);

res.add(arr);

return;

}

arr.add(node.val);

ArrayList left = (ArrayList)arr.clone();

ArrayList right = (ArrayList)arr.clone();

arr = null;

if(node.left!=null){

subPath(node.left,left,target-node.val);

}

if(node.right!=null){

subPath(node.right,right,target-node.val);

}

}

}

25.复杂链表的复制

27.字符串的排列

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

思路:递归。把字符串分为两个部分: 字符串的第一个字符,第一个字符后面的所有字符。1.求所有可能出现在第一个位置的字符,用索引遍历。2.求第一个字符以后的所有字符的全排列。将后面的字符又分成第一个字符以及剩余字符。

import java.util.ArrayList;

import java.util.TreeSet;

public class Solution {

public ArrayList Permutation(String str) {

ArrayList res = new ArrayList();

if(str == null || str.length() == 0)

return res;

TreeSet set = new TreeSet();

generate(str.toCharArray(), 0, set);

res.addAll(set);

return res;

}

public void generate(char[] arr, int index, TreeSet res){

if(index == arr.length)

res.add(new String(arr));

for(int i = index ; i < arr.length ; i++){

swap(arr, index, i);

generate(arr, index + 1, res);

swap(arr, index, i);

}

}

public void swap(char[] arr, int i, int j){

if(arr == null || arr.length == 0 || i < 0 || j > arr.length - 1)

return;

char tmp = arr[i];

arr[i] = arr[j];

arr[j] = tmp;

}

}

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

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

解法1:对数组进行排序,如果该数存在,那么就是排序数组中间的数,判断这个数的个数是否大于一半,如果是,返回这个数,否则返回0。时间复杂度:O(nlogn);空间复杂度:O(1)。

解法2:在遍历数组时保存两个值:一是数组中一个数字,一是次数。遍历下一个数字时,若它与之前保存的数字相同,则次数加1,否则次数减1;若次数为0,则保存下一个数字,并将次数置为1。遍历结束后,所保存的数字即为所求。最后验证这个数是否出现了一半以上。

public class Solution {

public int MoreThanHalfNum_Solution(int [] array) {

int res = array[0];

int count = 1;

for(int i=1;i

if(res==array[i])

count += 1;

else

count -= 1;

if(count==0){

res = array[i];

count = 1;

}

}

count = 0;

for(int j=0;j

if(array[j]==res)

count += 1;

}

if(count>array.length/2)

return res;

else

return 0;

}

}

29.最小的K个数

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

思路:堆排序,使用PriorityQueue或者自行构建最小堆。

import java.util.ArrayList;

import java.util.Comparator;

import java.util.PriorityQueue;

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() != 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) {

result.add(integer);

}

return result;

}

}

30.连续子数组的最大和

给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

输入: [-2,1,-3,4,-1,2,1,-5,4],

输出: 6

解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。

思路:需要两个变量,一个是global_max,从全局来看,每次最大的是什么组合,另一个是local_max,和global_max相比,更新global_max。

代码

public class Solution {

public int FindGreatestSumOfSubArray(int[] array) {

int local_max = array[0];

int global_max = array[0];

for(int i=1;i

local_max=Math.max(local_max+array[i],array[i]);

global_max=Math.max(global_max,local_max);

}

return global_max;

}

}

31.从1到n的整数中1出现的个数

比如,1-13中,1出现6次,分别是1,10,11,12,13。

public class Solution {

public int NumberOf1Between1AndN_Solution(int n) {

int count = 0;

for(int i=0;i<=n;i++){

int a=i;

while(a>0){

if(a%10==1)

count +=1;

a=a/10;

}

}

return count;

}

}

32.把数组排成最小的数

输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323。

思路: 根据题目的要求,两个数字m和n能拼接称数字mn和nm。如果mn

import java.util.ArrayList;

public class Solution {

public String PrintMinNumber(int [] numbers) {

int n;

StringBuilder s = new StringBuilder();

ArrayList list = new ArrayList<>();

n = numbers.length;

for (int i = 0; i < n; i++) {

list.add(numbers[i]);

}

list.sort((str1, str2) -> {

String s1 = str1 + "" + str2;

String s2 = str2 + "" + str1;

return s1.compareTo(s2);

});

list.forEach(s::append);

return s.toString();

}

}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值