Java实现剑指Offer_编程题(持续更新)

目录

1、二维数组中的查找

2、替换空格

4、重建二叉树

5、用两个栈实现队列

6、旋转数组的最小数

7、斐波那契数列

8、跳台阶

9、变态跳台阶

10、矩阵覆盖

11、二进制中1的个数

12、求1+2+3+...+n


1、二维数组中的查找

题目描述:

在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的

顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。

思路:

矩阵是有序的,从左下角来看,向上数字递减,向右数字递增。因此从左下角开始查找,当要查找数字比左下角数字大时

----右移,要查找数字比左下角数字小时----上移

代码实现:

public class Solution {

public boolean Find(int target, int [][] array) {
       int  len = array.length-1;//数组的一维长度
       int i = 0;//控制列数
       while (len >= 0 && i < array[0].length){
           if(array[len][i] > target){
               len--;
           }else if(array[len][i] < target){
               i++;
           }else{
               return true;
           }
       }
     return false;
     }
}

2、替换空格

题目描述:

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

为We%20Are%20Happy。

思路: 

方法一:开辟一个字符串替换

方法二:在当前字符串替换,怎么替换才更有效率(不考虑java里现有的replace方法)。从前往后替换,后面的字符要不

断往后移动,要多次移动,所以效率低下。从后往前,先计算需要多少空间,然后从后往前移动,则每个字符只为移动一

次,这样效率更高一点。

代码实现:

public class Solution {
 
    //方法一:开辟一个新的字符串做替换
    public String replaceSpace1(StringBuffer str) {
        String s = str.toString();
        char[] strchar = s.toCharArray();
        StringBuffer a = new StringBuffer();
        for(int i=0;i<strchar.length;i++){
            if(strchar[i]==' '){
                a.append("%20");
            }
            else{
                a.append(strchar[i]);
             }
        }
        return a.toString();
      }

     //方法二:在当前字符串做替换
     public String replaceSpace2(StringBuffer str) {
        //这个是使用java提供的函数进行解决。
        //String str2 = str.toString();
        //return str2.replace(" ","%20");	
        
        //第二种则是使用StringBuffer提供的特性解决
        int spaceNum = 0;//计算空格的数量
        for(int i = 0; i < str.length(); i ++){
            if(str.charAt(i) == ' '){
                spaceNum ++;
            }
        }
        int oldLen = str.length();//原str的长度
        int oldIndex = oldLen - 1;//这个是原str的最后一个的下标
        int newLen = oldLen + spaceNum * 2;//这个新的替换空格后的str的长度
        int newIndex = newLen - 1;//这个是新的str的最后一个字符的下标。
        
        str.setLength(newLen);//设置新的长度
        for(int j = oldIndex; j >=0 && j < newIndex; j--){
            if(str.charAt(j) == ' '){
                str.setCharAt(newIndex--, '0');
                str.setCharAt(newIndex--, '2');
                str.setCharAt(newIndex--, '%');
            }else{
                str.setCharAt(newIndex--, str.charAt(j));
            }
        }
        return str.toString();      
    }
    
}

3、从头到尾打印链表

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

思路:采用栈或者递归的思想来实现该ArrayList,栈的思想是先进后出,从而实现反向输出。采用递归的思想其实也是实

现先进后出的思想。做这道题首先要知道链表的数据结构,然后具体思想和步骤见代码。

代码实现:


	/**
	 * 3、从头到尾打印链表 
	 * 题目描述:
	               输入一个链表,按链表值从尾到头的顺序返回一个ArrayList。
	 */
        //方法一:先输入这个链表从头到尾的顺序,然后使用Collection自带的反转函数
	public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
		ArrayList<Integer> list = new ArrayList<Integer>();
		while (listNode != null) {
			list.add(listNode.val);
			listNode = listNode.next;
		}
		Collections.reverse(list);
		return list;
	}
        //方法二:采用递归的思想
	public ArrayList<Integer> printListFromTailToHead1(ListNode listNode) {
		ArrayList<Integer> list = new ArrayList<Integer>();
		if (listNode != null) {
                        //当节点不为空的时候,指向listNode的next域,
                        //直到listNode的next域为空,返回list
                        //此时在做前一个的printListFromTailToHead(listNode.next)的递归
                        //即最后一个节点,此时执行一行代码,添加节点值,输出节点
                        //再返回到上一个递归,以此列推,直至结束。
                      list=printListFromTailToHead(listNode.next);
			
                      list.add(listNode.val);
		}
                //直到listNode的next域为空,返回list
		return list;
	}

	public class ListNode {
		int val;
		ListNode next = null;

		ListNode(int val) {
			this.val = val;
		}
	}

4、重建二叉树

题目描述:输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都

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

思路:每次都让得到一个 根节点,然后让根节点指向其左右节点。左右节点有分别有自己的根节点。一次类推,递归到

最后没有左右节点为止为出口。

代码实现:

public class TreeNode {
	int val;
	TreeNode left;
	TreeNode right;

	TreeNode(int x) {
		val = x;
	}
}

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

    TreeNode root = reConstructBinaryTree(pre, 0, pre.length - 1, 
                                            in, 0,in.length - 1);
    return root;
}

// 前序遍历{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6}
private TreeNode reConstructBinaryTree(int[] pre, int startPre, 
                                      int endPre,int[] in, int startIn, int endIn) {

    if (startPre > endPre || startIn > endIn)
	return null;
    TreeNode root = new TreeNode(pre[startPre]);

    for (int i = startIn; i <= endIn; i++)
	if (in[i] == pre[startPre]) {
	    root.left = reConstructBinaryTree(pre, startPre + 1, startPre
						+ i - startIn, in, startIn, i - 1);
	    root.right = reConstructBinaryTree(pre, i - startIn + startPre
						+ 1, endPre, in, i + 1, endIn);
	    break;
	}

    return root;
}

5、用两个栈实现队列

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

思路:首先需要了解栈的数据结构,先进后出,那么用两个栈实现队列。入队列:直接压入元素至s1

出队列:如果s2不为空,把s2中的栈顶元素直接弹出,否则把s1中的所有元素弹出并依次压入s2,再弹出s2中的栈顶元素

代码实现:

Stack<Integer> stack1 = new Stack<Integer>();
	Stack<Integer> stack2 = new Stack<Integer>();

	public void push(int node) {
		if (stack1.isEmpty()) {
			while (stack2.size() != 0) {
				stack1.push(stack2.pop());
			}
			stack1.push(node);
		} else {
			stack1.push(node);
		}
	}

	public int pop() {
		if (stack2.isEmpty()) {
			while (stack1.size() != 0) {
				stack2.push(stack1.pop());
			}
			return stack2.pop().intValue();
		} else {
			return stack2.pop().intValue();
		}
	}

6、旋转数组的最小数

题目描述:把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。 输入一个非减排序的数组的一个

旋转,输出旋转数组的最小元素。例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。 NOTE:给出的所

有元素都大于0,若数组大小为0,请返回0。

思路:这个问题的中心思想其实就是使用二分查找的方法,逐步的逼近这个最小值,首先这个旋转数组将一个非递减的数

组分成了两个子数组,前一个数组的值都比后一个数组的值大,并且两个子数组都是非递减的数组,而且我们可以知道这

个最小值肯定是在前一个数组和后一个数组的交界出。也就是后一个数组的第一个值。(仔细讲解)

代码实现:

public int minNumberInRotateArray(int[] array) {

    if (array.length == 0) {
	return 0;
    }
    int low = 0;
    int high = array.length - 1;

    while (low < high) {

	int mid = low + (high - low) / 2;
	if (array[mid] > array[high]) {
	    low = mid + 1;
	} else if (array[mid] == array[high]) {
	    high = high - 1;
	} else {
	    high = mid;
	}

    }
    return array[low];
}

7、斐波那契数列

题目描述:大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项(从0开始,第0项

为0)。n<=39

思路:

代码实现:

8、跳台阶

题目描述: 一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序

不同算不同的结果)

思路:

代码实现:

9、变态跳台阶

题目描述: 一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有

多少种跳法。

思路:

代码实现:

10、矩阵覆盖

题目描述:我们可以用2*1的小矩形横着或者竖着去覆盖更大的矩形。请问用n个2*1的小矩形无重叠地覆盖一个2*n的大矩

形,总共有多少种方法?

思路:

代码实现:

11、二进制中1的个数

题目描述:输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。

思路:

代码实现:

12、求1+2+3+...+n

题目描述:求1+2+3+...+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。

思路:1.需利用逻辑与的短路特性实现递归终止。

   2.当n==0时,(n>0)&&((sum+=Sum_Solution(n-1))>0)只执行前面的判断,为false,然后直接返回0

   3.当n>0时,执行sum+=Sum_Solution(n-1),实现递归计算Sum_Solution(n)。

代码实现:

 public int Sum_Solution(int n) {
       int sum = n;
        boolean b = (sum > 0) && ((sum += Sum_Solution(sum-1))>0);
        return sum;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值