剑指Offer_______其他1

154 阅读5分钟

**15、二进制中1的个数 **

题目描述: 请实现一个函数,输入一个整数,输出该数二进制表示中1的个数。例如,把9表示成二进制是1001,有2位是1。因此,如果输入9,则该函数输出2。

解题思路\color{green}{解题思路}: 把一个整数减去1,再和原整数做‘与’运算,会把该整数最右边一个1变成0,其它位不变。那么一个整数的二进制有多少个1,就可以进行多少次这样的操作。

public class Solution {
    public int hammingWeight(int n) {
        int sum=0;	//计数器sum
        while(n!=0){
            n = n&(n-1);	//每次把n的二进制最后一个1变为0
            //n &= (n-1);
            sum++;
        }return sum;
    }
}

17、打印从1到最大的n位数

题目描述: 输入数字 n,按顺序打印出从 1 到最大的 n 位十进制数。比如输入 3,则打印出 1、2、3 一直到最大的 3 位数 999。
解题思路\color{green}{解题思路}: 暂不考虑大数问题

class Solution {
    public int[] printNumbers(int n) {
        int size=(int)Math.pow(10,n)-1;
        int[] array=new int[size];
        for(int i=0;i<size;i++){
            array[i]=i+1;
        }return array;
    }
}

**29、顺时针打印矩阵 **

**题目描述:**输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字
解题思路\color{green}{解题思路}:
通过一个flag变量去不断的去更新遍历矩阵下标x,y的值(通过越界和flag当前的值)

class Solution {
public ArrayList<Integer> printMatrix(int [][] matrix) {
        ArrayList<Integer> ans = new ArrayList<>();
        int flag = 1;// 1->right, 2->down, 3->left, 4->up
        int x = 0;
        int y = 0;
        boolean[][] vis = new boolean[matrix.length][matrix[0].length]; // 这个就是用来标记已经走过的点
        while (ans.size() < matrix.length * matrix[0].length) {
            if(x < 0 || x >= matrix.length || y < 0 || y >= matrix[0].length || vis[x][y]) { 
            // vis[x][y] -> 已经遍历过的位置也当作越界处理
                
                if(flag == 1) {
                    flag = 2; // 往下走
                    y--; // 消除越界的影响
                    x++; // 本质上就是到达下一个位置的横坐标
                } else if(flag == 2) {
                    flag = 3; // 往左走
                    x--; // 消除越界的影响
                    y--; // 本质上就是到达下一个位置的纵坐标
                } else if (flag == 3) {
                    flag = 4; // 往上走
                    y++; // 消除越界的影响
                    x--; // 本质上就是到达下一个位置的横坐标
                } else {
                    flag = 1;//往右走
                    x++; // 消除越界的影响
                    y++; // 本质上就是到达下一个位置的纵坐标
                }

            } else {
                ans.add(matrix[x][y]);
                vis[x][y] = true; // 去标记已经遍历过的位置
                // 根据flag的值更新遍历矩阵的下标x,y的值
                if(flag == 1) {
                    y++;
                } else if (flag == 2) {
                    x++;
                } else if (flag == 3) {
                    y--;
                } else {
                    x--;
                }
            }
        }
        return ans;
    }
}

30、包含min函数的栈

**题目描述:**定义栈的数据结构,请在该类型中实现一个能够得到栈的最小元素的 min 函数,在该栈中,调用 min、push 及 pop 的时间复杂度都是 O(1)
解题思路\color{green}{解题思路}:

/**
 * Your MinStack object will be instantiated and called as such:
 * MinStack obj = new MinStack();
 * obj.push(x);
 * obj.pop();
 * int param_3 = obj.top();
 * int param_4 = obj.min();
 */
class MinStack {
    Stack<Integer> s1;
    Stack<Integer> s2; 
 
    /** initialize your data structure here. */
    public MinStack() {
        s1=new Stack();
        s2=new Stack();  //s2是辅助栈
    }
    
    public void push(int x) {
        s1.push(x);
        //加等号的边界条件
        if(s2.isEmpty() || x<=s2.peek() ){	//注意if( )顺序,s2不空是s2.peek()的前提
            s2.push(x);
        }
    }
    
    public void pop() {
        if(s1.pop().equals(s2.peek())){	//无论是否,都会执行s1.pop()
            s2.pop();
        }
    }
    
    public int top() {
        return s1.peek();
    }
    
    public int min() {
        return s2.peek();
    }
}

31、栈的压入,弹出序列

**题目描述:**输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如,序列 {1,2,3,4,5} 是某栈的压栈序列,序列 {4,5,3,2,1} 是该压栈序列对应的一个弹出序列,但 {4,3,5,1,2} 就不可能是该压栈序列的弹出序列。
解题思路\color{green}{解题思路}:

class Solution {
    public boolean validateStackSequences(int[] pushed, int[] popped) {
        	Stack<Integer> stack=new Stack();
       		int i=0;  //poped的指针
            
            for(int j=0; j<pushed.length; j++){
            stack.push(pushed[j]);  //将pushed元素逐个放入栈中
            //for(int num : pushed){
            //stack.push(num);
            
            while(!stack.isEmpty() && stack.peek()== popped[i]){  //如果栈顶元素和poped元素相等,则将栈顶元素弹出
                stack.pop();
                i++;
            }
        }return stack.isEmpty();
    }
}

foreach循环的语句格式\color{red}{foreach循环的语句格式}:

for(数据类型 变量名:对象)  //for(int num : pushed)
	{  
     	//循环体为引用了变量的Java语句   //stack.push(num);
	}

33、二叉搜索树的后序遍历序列

题目描述: 输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历结果。如果是则返回 true,否则返回 false。假设输入的数组的任意两个数字都互不相同

解题思路\color{green}{解题思路}:

public class Solution{
public boolean verifyPostorder(int[] postorder) {
    return helper(postorder, 0, postorder.length - 1);
}

boolean helper(int[] postorder, int left, int right) {
    	//如果left==right,就一个节点不需要判断了,如果left>right说明没有节点,
    	//也不用再看了,否则就要继续往下判断
    if (left >= right){
        return true;
    }
    	//因为数组中最后一个值postorder[right]是根节点,这里从左往右找出第一个比
    	//根节点大的值,他后面的都是根节点的右子节点(包含当前值,不包含最后一个值,
    	//因为最后一个是根节点),他前面的都是根节点的左子节点
    int mid = left;
    int root = postorder[right];
    while (postorder[mid] < root){
        mid++;
    }
    int temp = mid;
    	//因为postorder[mid]前面的值都是比根节点root小的,
    	//我们还需要确定postorder[mid]后面的值都要比根节点root大,
    	//如果后面有比根节点小的直接返回false
    while (temp < right) {
        if (postorder[temp++] < root)
            return false;
    }
    	//然后对左右子节点进行递归调用
    return helper(postorder, left, mid - 1) && helper(postorder, mid, right - 1);
   }
}

34、二叉树中和为某一值的路径

**题目描述:**输入一棵二叉树和一个整数,打印出二叉树中节点值的和为输入整数的所有路径。从树的根节点开始往下一直到叶节点所经过的节点形成一条路径。

解题思路\color{green}{解题思路}:

class Solution {
    LinkedList<List<Integer>> res = new LinkedList<>();
    LinkedList<Integer> path = new LinkedList<>();  //初始化路径列表path
    
    public List<List<Integer>> pathSum(TreeNode root, int sum) {
        recur(root, sum);
        return res;
    }
    void recur(TreeNode root, int tar) {
        if(root == null) return;
        path.add(root.val);
        tar -= root.val;   //更新目标值tar
        if(tar == 0 && root.left == null && root.right == null)
            res.add(new LinkedList(path));
        recur(root.left, tar);
        recur(root.right, tar);
        path.removeLast();
    }
}

36、 二叉搜索树与双向链表

**题目描述:**输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向 解题思路\color{green}{解题思路}:

40、 最小的k个数

**题目描述:**输入整数数组 arr ,找出其中最小的 k 个数。例如,输入4、5、1、6、2、7、3、8这8个数字,则最小的4个数字是1、2、3、4。 解题思路1\color{green}{解题思路1}:

class Solution {
    public int[] getLeastNumbers(int[] arr, int k) {
        //最小堆
        Queue<Integer> queue=new PriorityQueue<>( (o1,o2)->o2.compareTo(o1) );
        for(int i:arr){
            queue.add(i);
            //维护堆的最大个数为k
            while(!queue.isEmpty()&&queue.size()>k){
                queue.poll();
            }
        }
        int[] res=new int[k];
        for(int i=0;i<k;i++){
            res[i]=queue.poll();
        }
        return res;
    }
}

解题思路2\color{green}{解题思路2}:

class Solution {
    public int[] getLeastNumbers(int[] arr, int k) {
        if(arr==null||arr.length==0){
            return new int[0];
        }
        int low=0; int high=arr.length-1;

        while(low<high){
            int index=partition(arr,low,high);
            if(index==k-1){break;}
           
            //index<k-1相当于想要获得80分,结果获得60分,只需要在61分以上寻找
            else if(index<k-1){low=index+1;}
            else{high=index-1;}
        }
        //返回arr数组中,第0到第k-1一共k个数
        return Arrays.copyOfRange(arr,0,k);
    }
    //partition函数
    public int partition(int[] arr,int low,int high){
        int piovt=arr[low];
        int index=low;
        for(int i=low;i<arr.length;i++){
            if(arr[i]<piovt){
                swap(arr,i,++index);
            }
        }
        swap(arr,low,index);
        return index;
}

    public void swap(int[] arr,int i,int j){
        int temp=arr[i];
        arr[i]=arr[j];
        arr[j]=temp;
    }
}

43、1~n整数中1出现的次数 解题思路1\color{green}{解题思路1}:暴力法,时间复杂度O(n*log(n))

class Solution {
    public int countDigitOne(int n) {
        int sum=0;  //统计出现1的个数
        for(int i=1;i<=n;i++){
            int x=i;
            while(x!=0){
                if(x%10==1){   //%是取余
                    sum++;
                }
                x=x/10;   //除号是取整
            }
        }
        return sum;
    }
}

49、丑数

题目描述: 我们把只包含质因子 2、3 和 5 的数称作丑数(Ugly Number)。例如6、8都是丑数,但14不是,因为它包含质因子7。习惯上我们把1当做是第一个丑数。求按从小到大的顺序的第N个丑数

解题思路\color{green}{解题思路}: 就是说通过去根据2* 丑数,3* 丑数,5* 丑数 这三个队列去判断出当前位置的值,然后去更新遍历这三个队列下标的值即可

public class solution{
public int GetUglyNumber_Solution(int index) {
        int[] a = new int[index];
        a[0] = 1;
        int index1 = 0; // 遍历丑数*2的队列
        int index2 = 0; // 遍历丑数*3的队列
        int index3 = 0; // 遍历丑数*5的队列

        for (int i = 1; i < index; i++) {
            a[i] = Math.min(Math.min(a[index1] * 2, a[index2] * 3) , a[index3] * 5);
            // 根据放在第i个位置上的数字更新遍历三个队列的下标
            if (a[i] == a[index1] * 2) {
                index1++;
            }
            if (a[i] == a[index2] * 3) {
                index2++;
            }
            if (a[i] == a[index3] * 5) {
                index3++;
            }
        }
        return a[index - 1];
    }
}