剑指offer-Java刷题心得

剑指offer
一.
Java查找二维数组时,如何确定二维数组的行列长度
确定二维数组行数:int rowLength = array.length;
确定二维数组列数:int colLength = array[0].length;

二。

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

解法一:
调用自带函数replaceAll()

解法二:
用新的StringBuffer存储,每当扫描到空格时就append("%20") ,否则扫到什么append什么

三.
List容器的下标从0开始

List ls = new ArrayList();
ls.add("first");
System.out.println(ls.get(0));

非递归思路:ArrayList 中有个方法是 add(index,value),可以指定 index 位置插入 value 值
所以我们在遍历 listNode 的同时将每个遇到的值插入到 list 的 0 位置,最后输出 listNode 即可得到逆序链表

递归代码:

public class Solution {    ArrayList<Integer> list = new ArrayList();
    public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
            if(listNode!=null){
                printListFromTailToHead(listNode.next);
                list.add(listNode.val);
            }
            return list;    
    }
}

四.旋转数组的最小数字

初始想法是顺序查找直到出现后一个数比前一个数字小的情况
看了题解后,可以采用时间复杂度更低的二分查找

五.斐波那契数列

递归解法并不难,重点是在存储和递归的优化需要好好研究一下。
https://www.nowcoder.com/questionTerminal/c6c7742f5ba7442aada113136ddea0c3?answerType=1&f=discussion

六.跳台阶
变形的斐波那契数列
dp(i) = dp(i-1)+dp(i-2)

七.变态跳台阶
变形的斐波那契数列
f(n) = f(n-1)+f(n-2)+f(n-3)+…
f(n-1) = f(n-2)+f(n-3)+…
上式-下式可得:f(n) = f(n-1)

斐波那契数列的变形掌握不够熟练!

八.矩阵覆盖
每次可以横向摆放覆盖一行剩余n-1行
也可以竖向摆放覆盖两行剩余n-2行
f(n) = f(n-1)+f(n-2)

九.二进制中1的个数
原码:第一位代表符号位。
反码:在原码的基础上,除符号位外,逐位取反。
补码:反码+1

直观思想:将输入数字与0xffffffff相与,再进行1的计数。

正常思路:将数字右移再与1相与,但负数右移会再右侧补1,因此可采用将1左移与数字相与的策略,直到将1移出计数范围变成0。

更好的思路:将数字-1后再与原数字做"&"运算,每次将原数字-1都会将原数字最右侧的1置为0,并且将该数字右侧的所有0转换为1,然后再将该转换后的数字与原数字相与,就相当于每次只把原数字最右侧的一个1置为0,于是原数字有多少个1就可以进行多少次这样的运算。

public int NumberOf1(int n) {
    int count = 0;
    while (n != 0) {
        count++;
        n = n & (n-1);
    }
    return count;
}

十.数值的整数次方
直观思路:直接采用循环的方式进行计算,需要考虑指数为负数的情况,需要将结果取倒数
时间复杂度O(n)。

递归想法:n为偶数,an=an/2 × an/2;
n为奇数an=(a(n-1)/2)*(a(n-1)/2)*a
时间复杂度O(logn)

十一.反转链表
思路:用三个节点分别存储当前头部的前一个节点,当前头部,头部的后一个节点。每次将当前头部的指针指向前部,在将头部的节点移动到当前头部,之前的后部节点变为head节点

public ListNode ReverseList(ListNode head) {
    ListNode pre = null;
    ListNode next = null;
    //pre->head->next
    //pre<-head next
    //temp<-pre head->next
    while (head != null) {
        next = head.next;
        head.next = pre;
        //pre move to the next node
        pre = head;
        head = next;
    }
    return pre;
}

十二.合并两个排序的链表
非常经典的一道题!

递归解法:
想法较为简单,首先判断当前两个链表是否为空,若一个为空则直接返回另一个,再判断两链表头节点数值的大小,若 list1 > list2 则将list2.next和list1继续合并,并将合并后的结果链接到list2上

public ListNode Merge(ListNode list1,ListNode list2) {
    if (list1 == null) return list2;
    else if (list2 == null) return list1;
    if (list1.val > list2.val) {
        list2.next = Merge(list2.next,list1);
        return list2;
    }
    else {
        list1.next = Merge(list1.next,list2);
        return list1;
    }
}

非递归解法:
多次出错的原因: 搞清楚定义头节点时应该将哪个部分进行初始化,应该将初始化空间的节点作为程序中进行操作的节点,后指向该节点的node作为真正的返回值,在结果处返回。

    public ListNode Merge(ListNode list1,ListNode list2) {
        ListNode p = new ListNode(0);//就是这个地方!
        ListNode ans = p;
        while (list1 != null && list2 != null) {
            if (list1.val < list2.val) {
                p.next = list1;
                p = p.next;
                list1 = list1.next;
            }
            else {
                p.next = list2;
                p = p.next;
                list2 = list2.next;
            }
        }
        if (list1 != null) p.next = list1;
        if (list2 != null) p.next = list2;
        return ans.next;
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章