zoukankan      html  css  js  c++  java
  • 剑指offer

    第三章 高质量代码

    面试题16 求base的exp次方

    处理边界样例,负样例

    • base = 0,exp >0,<0,=0三种情况
    • base != 0 ,exp >=0,<0 两种情况
    package nowcoder;
    import org.junit.Test;
    public class offer_16 {
    	boolean invalid = false; 
    	double power(double base,int exp) {
    		double eps = 1e-10;
    		invalid = false; 
    		
    		if( Math.abs(base-0) < eps && exp <= 0) {
    			invalid = true;
    			return 0; 
    		}
    		double absExp = Math.abs(exp);
    		if(exp<0)	return 1/getResult(base, exp);
    		else		return getResult(base, exp);
    			
    	}
    	double getResult(double base,int exp) {
    		if(exp == 1)		return base;
    		else if((exp&0x1) == 0){
    			double t = getResult(base, exp>>1);
    			return t*t;
    		}
    		else {
    			double t = getResult(base, exp>>1);
    			return t*t*base;
    		}
    	}
    	@Test
    	public void test() {
    		System.out.println(power(4, 3));
    		System.out.println(invalid);
    	}
    }
    

    面试题17 打印从1到最大的n位数

    弄清楚 n的范围,是否能用基本数据类型存储,需要考虑大数情况,利用数组来存数字或者使用DFS遍历

    package nowcoder;
    
    import javax.sound.midi.Instrument;
    
    import org.junit.Test;
    
    public class offer_17 {
    	public void print1ToMax(int num) {
    		short[] number = new short[num];
    		for(int i =0;i<num;i++)	number[i] = 0;
    		while(!increment(number)) {
    			printNumber(number);
    		}
    	}
    	public boolean increment(short[] number) {
    		int len = number.length;
    		int c = 0;
    		number[len-1]++;
    		for(int i = len-1;i>=0;i--) {
    			number[i] = (short) (number[i] +c);
    			c = number[i] / 10;
    			if(number[i] >= 10) {
    				if(i == 0) {
    					return true;
    				}else {
    					number[i] = (short) (number[i] - 10);
    				}
    			}else {
    				break;
    			}
    				
    		}
    		return false;
    	}
    	public void printNumber(short[] number) {
    		boolean flag = true;
    		for(int i= 0;i<number.length;i++) {
    			if(number[i] == 0 && flag)	continue;
    			else {
    				flag = false;
    				System.out.print(number[i]);
    			}
    		}
    		System.out.println();
    	}
    	public void print1ToMaxDFS(int num) {
    		short[] number = new short[num];
    		dfs(number,0);
    	}
    	public void dfs(short[] number,int index) {
    		if(index == number.length) {
    			printNumber(number);
    			return;
    		}
    		for(int i = 0;i<10;i++) {
    			number[index]++;
    			dfs(number,index+1);
    		}
    	}
    	@Test
    	public void test() {
    		print1ToMax(2);
    	}
    	@Test
    	public void test2() {
    		print1ToMax(4);
    	}
    }
    
    

    面试题18 删除链表的节点

    此处不是直接删除,而是将删除节点的下一个节点覆盖到该节点,然后删除下一个节点

    /*
     public class ListNode {
        int val;
        ListNode next = null;
    
        ListNode(int val) {
            this.val = val;
        }
    }
    */
    public class Solution {
        public ListNode deleteDuplication(ListNode pHead)
        {
            if(pHead == null || pHead.next == null)    return pHead;
            ListNode p = new ListNode(-1);
            p.next = pHead;
            pHead = p;
            
            ListNode Node = pHead.next;
            ListNode preNode = pHead;
            ListNode nextNode = null;
    
            while( Node!= null && Node.next!=null){
                nextNode = Node.next;
                if(Node.val == nextNode.val){
                    while(nextNode!= null &&  Node.val == nextNode.val){
                        nextNode = nextNode.next;
                    }
                    preNode.next = nextNode;
                    Node = nextNode;
                }else{
                    preNode = Node;
                    Node = Node.next;
                }
            }
            return pHead.next;
    
        }
    }
    
    

    面试题19 正则表达式匹配

    传送门
    将str和pattern分为四种情况讨论

    • str为空,pattern不为空
    • str不为空,pattern为空
    • str 和pattern为空
    • str和pattern都不为空
    public class Solution {
        public boolean match(char[] str, char[] pattern)
        {
            if(str == null || pattern == null)    return false;
            return matchCore(str,pattern,0,0);
        }
        public boolean matchCore(char[] str,char[] pattern,int strIndex,int patternIndex){
            if(strIndex == str.length && patternIndex == pattern.length)
                return true;
            else if(strIndex != str.length && patternIndex == pattern.length)
                return false;
            else if(strIndex == str.length && patternIndex != pattern.length){
                if(patternIndex +1 < pattern.length && pattern[patternIndex+1] == '*' )
                    return matchCore(str,pattern,strIndex,patternIndex+2);
                else
                    return false;
            }
            else{
                if(patternIndex+1 < pattern.length && pattern[patternIndex+1] == '*'){
                        //*前面的字符匹配成功
                    if( (strIndex <str.length &&pattern[patternIndex] == str[strIndex] )||(pattern[patternIndex]=='.' && strIndex!=str.length )){
                        //匹配,进入下一个状态
                        return matchCore(str,pattern,strIndex+1,patternIndex+2) ||
                        // 匹配成功,继续匹配,即*视为大于1
                            matchCore(str,pattern,strIndex+1,patternIndex)||
                         // 跳过 ,将*视为0
                            matchCore(str,pattern,strIndex,patternIndex+2);
                    }else{
                        //*前面的字符没有匹配成功,*视为0次
                        return matchCore(str,pattern,strIndex,patternIndex+2);
                    }
                }else{
                    if((strIndex < str.length && str[strIndex] == pattern[patternIndex] )|| (pattern[patternIndex] == '.' &&strIndex != str.length))
                       return matchCore(str,pattern,strIndex+1,patternIndex+1);
                    else
                        return false;
                }
            }
        }
    }
    

    面试题21 调整数组顺序使奇数位于偶数前面

    传送门
    1、双指针方法,复杂度o(n),不能保证原来奇数和偶数各自相对位置

    public class Solution {
        public void reOrderArray(int[] array) {
            int left = 0,right = array.length-1;
            while(left<right){
                while(left < right && (array[left]&0x1) != 0)
                    left ++;
                while(left < right && (array[right]&0x1) == 0)
                    right --;
               if(left<right){
                   int temp = array[left];
                    array[left] = array[right];
                    array[right] = temp;
               }
            }
        }
    }
    

    2、插入排序、冒泡排序思想,复杂度o(n),能够保证原来相对位置

    public class Solution {
        public void reOrderArray(int[] array) {
            for(int i = 1;i<array.length;i++){
                int temp = array[i];
                int j = i-1;
                if(array[i]%2 == 1){
                    for(;j>=0;j--){
                        if((array[j]&0x1) == 1){
                            break;
                        }else
                            array[j+1]= array[j];
                    }
                    array[j+1] = temp;
                }else{
                    continue;
                }
            }
        }
    }
    

    面试题22 链表中倒数第k个节点

    传送门
    方法1:遍历两次链表
    方法2:通过快慢指针方式,首先快指针先走k-1步,然后两个指针一起往后走,知道快指针先到达最后重点。
    为了保证鲁棒性,需要考虑边缘情况,链表为空,k为0或者链表中节点数目小于k。
    举一反三,获取链表中间节点,也可通过双指针方式,一个一次走两步,一个一次走一步。

    /*
    public class ListNode {
        int val;
        ListNode next = null;
    
        ListNode(int val) {
            this.val = val;
        }
    }*/
    public class Solution {
        public ListNode FindKthToTail(ListNode head,int k) {
            if(head == null || k == 0)    return null;
            ListNode first = head,last = head;
            for(int i = 0;i<k-1;i++){
                if(first.next!=null)    first=first.next;
                else    return null;
            }
            while(first.next!=null){
                first = first.next;
                last = last.next;
            }
            return last;
        }
    }
    

    面试题23 链表中环的入口节点

    同样采用快慢指针方式,我们注意到第一次相遇时
    慢指针走过的路程S1 = 非环部分长度 + 弧A长
    快指针走过的路程S2 = 非环部分长度 + n * 环长 + 弧A长
    S1 * 2 = S2,可得 非环部分长度 = n * 环长 - 弧A长
    让指针A回到起始点后,走过一个非环部分长度,指针B走过了相等的长度,也就是n * 环长 - 弧A长,正好回到环的开头。
    为了保证鲁棒性,需要考虑链表是否存在环问题。

    /*
     public class ListNode {
        int val;
        ListNode next = null;
    
        ListNode(int val) {
            this.val = val;
        }
    }
    */
    public class Solution {
    
        public ListNode EntryNodeOfLoop(ListNode pHead)
        {
            ListNode slow = pHead,fast = pHead;
            while(fast!=null && fast.next!=null){
                fast = fast.next.next;
                slow = slow.next;
                if(fast == slow)
                    break;
            }
            if(fast == null || fast.next == null)    return null;
            slow = pHead;
            while(slow != fast){
                slow = slow.next;
                fast = fast.next;
            }
            return slow;
        }
    }
    

    面试题24 反转链表

    /*
    public class ListNode {
        int val;
        ListNode next = null;
        ListNode(int val) {
            this.val = val;
        }
    }*/
    public class Solution {
        public ListNode ReverseList(ListNode head) {
            ListNode pre = null;
            ListNode pNode = head;
            ListNode pNext = null;
            while(pNode != null){
                pNext = pNode.next;
                pNode.next = pre;
                pre = pNode;
                pNode = pNext;
            }
            return pre;
        }
    }
    

    面试题25 合并两个排序链表

    /*
    public class ListNode {
        int val;
        ListNode next = null;
    
        ListNode(int val) {
            this.val = val;
        }
    }*/
    public class Solution {
        public ListNode Merge(ListNode list1,ListNode list2) {
            ListNode head = new ListNode(0);
            ListNode t = head;
            while(list1 != null && list2!= null){
                if(list1.val <= list2.val){
                    t.next = list1;
                    list1 = list1.next;
                    t = t.next;
                    t.next = null;
                }else{
                    t.next = list2;
                    list2 = list2.next;
                    t = t.next;
                    t.next = null;
                }
            }
            if(list1 == null){
                t.next = list2;
            }else{
                t.next = list1;
            }
            return head.next;
        }
    }
    

    面试题26 树的子结构

    分两步,第一步找到A树与树B的根节点相同的节点,采用DFS或BFS方法,第二步继续后续判断左子节点和右子节点是否相同。

    /**
    public class TreeNode {
        int val = 0;
        TreeNode left = null;
        TreeNode right = null;
    
        public TreeNode(int val) {
            this.val = val;
    
        }
    
    }
    */
    public class Solution {
        public boolean HasSubtree(TreeNode root1,TreeNode root2) {
            if(root1 == null || root2 == null)    return false;
            boolean flag = false;
            if(root1.val == root2.val){
               flag = equal(root1,root2);
            if(flag == false)
               flag = HasSubtree(root1.left,root2) || HasSubtree(root1.right,root2);
            }
            return flag;
        }
        public boolean equal(TreeNode node1,TreeNode node2){
            if(node2 == null)    return true;
            if(node1 == null && node2!= null)    return false;
            if(node1.val == node2.val)
                return equal(node1.left,node2.left) && equal(node1.right,node2.right);
            else{
                return false;
            }
        }
    }
    

    面试题27 二叉树的镜像树

    /**
    public class TreeNode {
        int val = 0;
        TreeNode left = null;
        TreeNode right = null;
    
        public TreeNode(int val) {
            this.val = val;
    
        }
    
    }
    */
    public class Solution {
        public void Mirror(TreeNode root) {
            dfs(root);
        }
        public void dfs(TreeNode node){
            if(node == null)    return;
            TreeNode t = node.right;
            node.right = node.left;
            node.left = t;
            dfs(node.left);
            dfs(node.right);
            return;
        }
    }
    

    面试题28 对称的二叉树

    /*
    public class TreeNode {
        int val = 0;
        TreeNode left = null;
        TreeNode right = null;
    
        public TreeNode(int val) {
            this.val = val;
    
        }
    
    }
    */
    public class Solution {
        boolean isSymmetrical(TreeNode pRoot)
        {
            if(pRoot == null)
                return true;
            else
                return dfs(pRoot.left,pRoot.right);
        }
        boolean dfs(TreeNode node1,TreeNode node2){
            if(node1 == null && node2 != null)    return false;
            if(node1 != null && node2 == null)    return false;
            if(node1 == null && node2 == null)    return true;
            if(node1.val == node2.val){
                return dfs(node1.left,node2.right) && dfs(node1.right,node2.left);
            }
            return false;
        }
    }
    

    面试题30 包含min函数的栈

    传送门

    import java.util.Stack;
    
    public class Solution {
        //
        int N = 1000;
        int[] stack = new int[N];
        int[] h = new int[N];
        int index = -1;
        int t = -1;
        public void push(int node) {
            stack[++index] = node;
            if(t == -1){
                h[++t] = index;
            }else if(node < stack[h[t]]){
                h[++t] = index;
            }
        }
    
        public void pop() {
            if(index<0)    return;
            else if(index == h[t]){
                t--;
                index--;
            }else{
                index--;
            }
            return;
        }
        
        public int top() {
            return stack[index];
        }
        
        public int min() {
            return stack[h[t]];
        }
    }
    

    面试题34:二叉树中和为某一值的路径

    这题是采用深度优先搜索方法遍历所有路径,搜索故过程中将节点保存在List中,当搜索到叶子节点时并且总和为target时则写入ret。然后继续搜索左子节点和右子节点。注意的是回溯的时候需要path中加入的元素删除掉。
    传送门

    import java.util.ArrayList;
    /**
    public class TreeNode {
        int val = 0;
        TreeNode left = null;
        TreeNode right = null;
        public TreeNode(int val) {
            this.val = val;
        }
    }
    */
    public class Solution {
        ArrayList<Integer> path = new ArrayList<>();
        ArrayList<ArrayList<Integer>> ret = new ArrayList<ArrayList<Integer>>();
        public ArrayList<ArrayList<Integer>> FindPath(TreeNode root,int target) {
            if(root == null)    return ret;
            dfs(root,target,0);
            ret.sort((a,b)->b.size()-a.size());
            return ret;
        }
        public void dfs(TreeNode node,int target,int sum){
            path.add(node.val);
            sum += node.val;
            if(sum == target && node.left == null && node.right == null){
                 ArrayList<Integer> t = new ArrayList<>();
                 t.addAll(path);
                 ret.add(t);
            }
            if(node.left != null){
                dfs(node.left,target,sum);
            }
            if(node.right!= null){
                dfs(node.right,target,sum);
            }
             path.remove(path.size()-1);
            return;
        }
    }
    

    复制复杂链表

    传送门
    1、在原链表中每个节点的后面赋值一个新的节点。
    2、更新每个新节点的随机指针值。
    3、将链表拆分成两个链表。

    /*
    public class RandomListNode {
        int label;
        RandomListNode next = null;
        RandomListNode random = null;
     
        RandomListNode(int label) {
            this.label = label;
        }
    }
    */
    public class Solution {
        public RandomListNode Clone(RandomListNode pHead)
        {
            if(pHead == null)    return null;
            RandomListNode head = pHead;
            while(head!=null){
                RandomListNode t = new RandomListNode(head.label);
                t.next = head.next;
                head.next = t;
                head = t.next;
            }
            head = pHead;
            while(head != null){
                head.next.random = head.random==null ? null:head.random.next;
                head = head.next.next;
            }
            RandomListNode ret = pHead.next;
            head = ret;
            RandomListNode h = pHead;
            while(head.next!=null){
                h.next = head.next;
                h = h.next;
                head.next = head.next.next;
                head = head.next;
            }
            h.next = null;
            return ret;
        }
    }
    

    二叉搜索树与双向链表

    传送门
    1、很明显中序遍历的结果就是链表的顺序。
    2、以根节点为例,先获取左子树的形成的链表,该链表中最后一个元素为最大值,根节点需要与其相连。然后生成右子树形成的链表,该链表中第一个元素需要与根节点相连。考虑到需要左子树链表的最后一个元素,需要右子树的第一个元素,第一个元素作为函数的返回值,最后一个元素用过一个全局变量记录。

    /**
    public class TreeNode {
        int val = 0;
        TreeNode left = null;
        TreeNode right = null;
    
        public TreeNode(int val) {
            this.val = val;
        }
    }
    */
    public class Solution {
        TreeNode last;    //全局变量,用于记录已经生成的链表的最右边节点。
        //以根节点为例,确定递归函数的返回值。
        public TreeNode Convert(TreeNode pRootOfTree) {
            if(pRootOfTree == null)    return null;
            if(pRootOfTree.left == null && pRootOfTree.right == null){
                last = pRootOfTree;
                return last;
            }
            TreeNode left = Convert(pRootOfTree.left);
            if(left!=null){
                pRootOfTree.left = last;
                last.right = pRootOfTree;
            }
            last = pRootOfTree;
            TreeNode right = Convert(pRootOfTree.right);
            if(right!=null){
                pRootOfTree.right = right;
                right.left = pRootOfTree;
            }
            return left==null?pRootOfTree:left;
        }
    }
    

    序列化二叉树

    传送门
    先序遍历二叉树,那反序列化时第一个读取到的数就是根节点的值。

    /*
    public class TreeNode {
        int val = 0;
        TreeNode left = null;
        TreeNode right = null;
    
        public TreeNode(int val) {
            this.val = val;
    
        }
    
    }
    */
    public class Solution {
        StringBuilder ret = new StringBuilder();
        String[] r;
        int index = -1;
        String Serialize(TreeNode root) {
            dfs(root);
            return ret.toString();
      }
        public void dfs(TreeNode node){
            if(node == null)    ret.append("#,");
            else{
                ret.append(node.val);
                ret.append(",");
                dfs(node.left );
                dfs(node.right);
            }
            return;
        }
        public TreeNode dfsD(){
             index += 1;
            if(index < r.length){
                if(r[index].equals("#")){
                    return null;
                }
                TreeNode node = new TreeNode(Integer.parseInt(r[index]));
                node.left = dfsD();
                node.right = dfsD();
                return node;
            }
            return null;
        }
        TreeNode Deserialize(String str) {
            r = str.split(",");
            return dfsD();
      }
    }
    

    38 字符串的排列

    给一个字符串,求出他的所有排列可能性,并以字典序输出。
    分析:将该问题分解为若干个子问题来解决。对于字符串abc,第一步求出所有可能出现在第一个位置的字符,即把第一个字符与后面的字符进行交换。第二步固定第一个字符位置,求后面字符的所有排列可能。
    传送门

    import java.util.*;
    public class Solution {
        public ArrayList<String> Permutation(String str) {
            ArrayList<String> ret = new ArrayList<>();
            if(str!=null&&str.length()!=0){
                 char[] s = str.toCharArray();
                 dfs(s,0,ret);
                 Collections.sort(ret);
            }
           return ret;
        }
        public void dfs(char[] ch ,int index, ArrayList<String> ret){
            if(index == ch.length){
                ret.add(String.valueOf(ch));
            }
            for(int j = index;j<ch.length;j++){
                if(j == index||ch[j]!=ch[index]){
                    swap(ch,j,index);
                    dfs(ch,index+1,ret);
                    swap(ch,j,index);
                }
            }
        }
        public void swap(char[] ch,int x,int y){
            char t = ch[x];
            ch[x] = ch[y];
            ch[y] = t;
            return;
        }
    }
    

    字符串的组合

    该题是上面一题的扩展,对于abc它的所有存在的组合包括a、b、c、ab、ac、bc、abc。对于长度为n的字符串x,求长度为m的组合,第一个字符可能是x的第一个字符,然后在剩下n-1的长度里取m-1个,也可能是n-1个字符里取m个字符。

    package nowcoder;
    
    import java.awt.event.ItemEvent;
    import java.lang.annotation.Retention;
    import java.lang.reflect.Array;
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.Collections;
    import java.util.HashSet;
    import java.util.LinkedList;
    import java.util.List;
    import java.util.Set;
    import java.util.Vector;
    import org.junit.Test;
    public class TestSplit {
    
    	public static void Func(int len,char[] s,int index,List<Character> ret) {
    		if(len == 0) {
    			for(char ch : ret) {
    				System.out.print(ch);
    			}
    			System.out.println();
    			return;
    		}
    		if(index == s.length) {
    			return;
    		}
    		ret.add(s[index]);
    		Func(len-1, s, index+1, ret);
    		ret.remove(ret.size()-1);
    		Func(len, s, index+1, ret);
    		
    	}
        public static void main(String[] args) {
        		String pString = "abc";
        		char[] s = pString.toCharArray();
        		for(int i = 1;i<=s.length;i++) {
        			List<Character> ret= new ArrayList<>();
        			Func(i,s,0,ret);
        		}
        }
    }
    

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

    方法一:基于快排思想找到排序数组中位于索引n/2出的元素,因为如果某个数字个数超过一半,那么该数字一定会在n/2处出现一次,通过快排中Partition能够将基数放置到合适位置,如果位置位于n/2处,则找到,然后验证过即可。如果不是,继续对左边或者右半边使用partition函数查找。

    public class Solution {
            public int MoreThanHalfNum_Solution(int [] array) {
            int len = array.length;
            if(len == 0)    return 0;
            int mid = len>>1;
            int index = Partition(array,0,len-1);
            int end =len-1;
            int start = 0;       
            while(index!=mid){
                if(index < mid){
                    start = index+1;
                    index = Partition(array,start,end);
                }else{
                    end = index -1;
                    index = Partition(array,start,end);
                }
            }
            int count = 0;
            for(int i = 0;i<len;i++){
                if(array[index] == array[i]){
                    count++;
                }
            }
            return count>len/2?array[index]:0;
        }
        public int Partition(int[] array,int left, int right){
        	 
            int temp = array[left];
            while(left<right){
             	
                while(right>left&&array[right]>=temp){
                    right--;
               
                }
            
                array[left] = array[right];
                while(right>left&&array[left]<=temp){
                    left++;
                }
                array[right] = array[left];
            }
            array[left] = temp;
            return left;
        }
    }
    

    方法二:摩尔投票法。

    public class Solution {
        public int MoreThanHalfNum_Solution(int [] array) {
            if(array.length == 0)    return 0;
            int count = 1;
            int num=array[0];
            for(int i = 1;i<array.length;i++){
                if(array[i] == num){
                    count++;
                }else{
                    count--;
                    if(count == 0){
                        num=array[i];
                        count = 1;
                    }
                }
            }
            count =0;
            for(int i  = 0;i<array.length;i++){
                if(array[i] == num){
                    count++;
                }
            }
            return count>array.length/2?num:0;
        }
    }
    

    面试题40 最小的k个数
    1、基于快排的思想,把输入的n个整数排序,位于最前面的k个数就是最小的k个数。基于数组的第k个数调整,比该数小的位于数组左边,比k大的位于右边即可。

    import java.util.*;
    public class Solution {
        public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
            ArrayList<Integer> a = new ArrayList<>();
            if(input == null || input.length == 0 || input.length<k || k == 0)    return a;
            int start = 0,end = input.length-1;
            int index = Partition(input,start,end);
            while(index!=k-1){
                if(index<k-1){
                    start = index + 1;
                    index = Partition(input,start,end);
                }else{
                    end = index-1;
                    index = Partition(input,start,end);
                }
            }
            for(int i= 0;i<k;i++){
                a.add(input[i]);
            }
            return a;
        }
        public int Partition(int[] input,int s, int e){
            int t = input[s];
            while(s<e){
                while( s < e && input[e] >= t){
                    e--;
                }
                input[s] = input[e];
                while(s<e && input[s]<= t){
                    s++;
                }
                input[e] = input[s];
            }
            input[s] = t;
            return s;
        }
    }
    

    2、最大堆,构造一个容量为k的元素的最大堆。当堆不满时候,往里面插入数字。当堆满时,堆顶数字则为最大数字,将该数字与插入数字对比,如果堆顶数字更大,则删除堆顶数字,将插入数字插入,否则跳过。
    PriorityQueue底层使用堆实现,构造优先队列时候需要传入一个实现Comparator接口的对象。

    import java.util.*;
    public class Solution {
        public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
            ArrayList<Integer> a = new ArrayList<>();
            if(input == null || input.length == 0 || input.length<k || k == 0)    return a;
            PriorityQueue<Integer> q = new PriorityQueue<>(k,new Comparator<Integer>(){
                public int compare(Integer x,Integer y){
                    return y-x;
                }
            });
            for(int i = 0;i<input.length;i++){
                if(q.size()<k){
                    q.add(input[i]);
                }else{
                    int t = q.element();
                    if(input[i] >= t){
                        continue;
                    }else{
                        q.remove();
                        q.add(input[i]);
                    }
                }
            }
            while(!q.isEmpty()){
                a.add(q.element());
                q.remove();
            }
            return a;
        }
    }
    

    面试题42 连续子数组的最大和

    动态规划方法:

    public class Solution {
        public int FindGreatestSumOfSubArray(int[] array) {
            int len = array.length;
            int[] dp= new int[len];
            dp[0] = array[0];
            int ret = dp[0];
            for(int i = 1;i<len;i++){
                dp[i]  = Math.max(dp[i-1]+array[i],array[i]);
                ret = Math.max(dp[i],ret);
            }
            return ret;
        }
    }
    

    找规律:

    public class Solution {
        public int FindGreatestSumOfSubArray(int[] array) {
            int len = array.length;
            int ret = array[0];
            int sum = ret;
            for(int i = 1;i<len;i++){
                if(sum<0){
                    sum = array[i];
                    ret = Math.max(ret,sum);
                }else{
                    sum += array[i];
                    ret = Math.max(ret,sum);
                }
            }
        }
    }
    

    面试题43:1~n整数中1出现的次数

    分析0-9 出现次数1,10-99 :101+10=20,0-999:2010+100=300,0-9999:30010+1000=4000,以7245举例,可以先千求1~7000中1的个数,为3007+1000,如果千位为1,则3001+146。然后计算 千位为7时7000~7199出现1的个数,202+100,然后计算7200~7239之间1的个数,1*4+10,最后加上个位的1。

    public class Solution {
        public int NumberOf1Between1AndN_Solution(int n) {
            int[] d = new int[10];
            d[1] = 1;
            d[0] = 0;
            int[] w = new int[10];
            for(int i = 2;i<=9;i++){
                d[i] = d[i-1]*10+(int)Math.pow(10,i-1);
            }
            int len = 0;
            int t = n;
            while(t>0){
                w[len+1] = t%10;
                len++;
                t = t/10;
            }
            int ret = 0;
            for(int i =len;i>=1;i--){
                if(w[i]>=2){
                    ret = ret + d[i-1]*w[i] + (int)Math.pow(10,i-1);
                }else if(w[i] == 1){
                    ret = ret +d[i-1] + func(w,i-1);
                }else{
                    continue;    
                }
            }
            return ret;
        }
        public int func(int[] w,int x){
            int ret=0;
            for(int i = x;i>=1;i--){
                ret = ret * 10 +w[i];
            }
            return ret+1;
        }
    }
    

    面试题44 数字序列中某一位的数字

    数字以012345678910111213141516...的格式序列化为一个字符序列,第5位为5(从0开始),第13位为1,第19位为4,求任意第n位对应的数字。
    0-9有10位,10-99 有902=180位,100-999有3900=2700位,以求第1001位举例,1001大于10,则求10开始的第991位,991大于180,则求100开始的第811位,811小于2700,则肯定在100-999之间,822=270*3+1,则为370中间一位,为1。
    传送门

    package nowcoder;
    public class offer44 {
    	public int func(int n) {
    		int[] dp = new int[10];
    		dp[1] = 10;
    		int num = n;
    		for(int i =2;i<7;i++) {
    			dp[i] = (int)Math.pow(10, i-1)*9*i; 
    		}
    		int i = 1;
    		for(i = 1;i<10;i++) {
    			if(num-dp[i]>0) {
    
    				num -= dp[i];
    			}else {
    				break;
    			}
    		}
    		int k = num%i;
    		int t = num/i+(int)Math.pow(10, i);
    		int l = i-k;
    
    		while(l>1) {
    			t = t/10;
    			l--;
    		}
    		return t%10;
     	}
    	public static void main(String[] args) {
    		offer44 pOffer44 = new offer44();
    		System.out.println(pOffer44.func(5));
    		System.out.println(pOffer44.func(13));
    		System.out.println(pOffer44.func(19));
    	}
    }
    

    把数组排成最小的数

    传送门
    对数组进行排序即可,比较m和n大小,如果mn<nm,则m<n.

    import java.util.*;
    
    public class Solution {
        public String PrintMinNumber(int [] numbers) {
            if(numbers==null|| numbers.length == 0)    return "";
            Integer[] q = new Integer[numbers.length];
            for(int i =0;i<numbers.length;i++){
                q[i] = numbers[i];
            }
            Arrays.sort(q,new Comparator<Integer>(){
                public int compare(Integer x,Integer y){
                    int a = countOfIntegers(x,y);
                    int b = countOfIntegers(y,x);
                    return a-b;
                }
            });
            
            StringBuffer p = new StringBuffer("");
            for(int i =0;i<numbers.length;i++){
                
                p.append(q[i]+"");
            }
            return p.toString();
            
        }
        public int countOfIntegers(int x,int num){
            int ret=1;
            int t= num;
            while(num>0){
               ret*=10;
               num = num/10;
            }
            return x*ret+t;
        }
    }
    

    面试题46 把数字翻译成字符串

    方法1:自顶向下递归搜索,但会重复解决子问题。

    package nowcoder;
    
    import java.text.DateFormatSymbols;
    import java.util.*;
    
    public class offer46 {
    	public static int DFS(char[] x,int index) {
    		if(index+1<x.length) {
    			char a = x[index];
    			char b = x[index+1];
    			int num = (a-'0')*10+b-'0';
    			if(num<=25) {
    				return DFS(x, index+2)+DFS(x, index+1);
    			}else {
    				return DFS(x, index+1);
    			}
    		}else {
    			return 1;
    		}
    	}
    	public static void main(String[] args) {
    		String pString = "12258";
    		char[] p = pString.toCharArray();
    		System.out.println(DFS(p,0));
    	}
    }
    

    2、动态规划

    package nowcoder;
    
    import java.text.DateFormatSymbols;
    import java.util.*;
    
    public class offer45 {
    	public static int DFS(char[] x,int index) {
    		int len = x.length;
    		int[] dp = new int[len+1];
    		for(int i = 0;i<len+1;i++)	dp[i] = 0;
    		dp[len-1] = 1;
    		dp[len] = 0;
    		for(int i = len-2;i>=0;i--) {
    			char a = x[i+1];
    			char b = x[i];
    			int t = (b-'0')*10+a-'0';
    			if(t<=25) {
    				dp[i] = dp[i] + dp[i+2] + dp[i+1];
    			}else {
    				dp[i] = dp[i+1];
    			}
    		}
    		return dp[0];
    	}
    	public static void main(String[] args) {
    		String pString = "12345";
    		char[] p = pString.toCharArray();
    		System.out.println(DFS(p,0));
    	}
    }
    

    面试题65 不用加减乘除法做加法

    通过位运算来实现加法,这里注意首先不进位加法t= x ^ y,通过异或运算完成,进位通过与运算再移位 c = x & y,最后c 与t相加,下一步循环执行。

    package nowcoder;
    
    public class Offer_65 {
    	public static void solution(int x,int y) {
    		int t = 0;
    		int c= 0 ;
    		while(true) {
    			t = x^y;
    			c = (x & y)<<1;
    			if(c == 0)	break;
    			x = t;
    			y = c;
    		}
    		System.out.println(t);
    	}
    	public static void main(String[] args) {
    		// TODO Auto-generated method stub
    		Offer_65.solution(121234, 22);
    	}
    }
    

    通过位运算交换两个数字

    package nowcoder;
    
    public class Offer_65_2 {
    	public static void solution(int x, int y) {
    		x = x+y;
    		y = x - y;
    		x = x -y;
    		System.out.println(x+" "+y);
    	}
    	public static void main(String[] args) {
    		// TODO Auto-generated method stub
    		Offer_65_2.solution(5,6);
    	}
    }
    
  • 相关阅读:
    [转载]Javascript:history.go()和history.back()的用法和区别
    微信商户平台,开通企业付款到用户功能
    使用ASP.Net WebAPI构建REST服务——客户端
    在WebAPI使用Session
    在asp.net一般应用程序中使用session
    Web Api Post注意事项
    WebAPI返回数据类型解惑
    c#中const与readonly区别
    sql之left join、right join、inner join的区别
    C#实现json的序列化和反序列化
  • 原文地址:https://www.cnblogs.com/a1225234/p/11991457.html
Copyright © 2011-2022 走看看