剑指offer面试题2:单例模式,面试题3:数组中重复的数字,面试题4:二维数组中的查找,面试题5:替换空格

面试题2:单例模式
  • 单例模式的三个典型特点:
  1. 只有一个实例
  2. 自我实例化
  3. 提供全局访问点
  • 饿汉模式、非线程安全的懒汉模式、线程安全的懒汉模式。
面试题3. 数组中重复的数字

在这里插入图片描述

① 暴力法:先排序再查找
public boolean duplicate(int numbers[], int length, int[] duplication) {
    // 特殊情况,数组长度为0或者1,不可能存在重复数字
    if (length <= 1) {
        return false;
    }
    // 使用Java API对数组进行排序
    Arrays.sort(numbers);
    // 前后的数字相同,说明有重复数字
    for (int i = 0; i < length - 1; i++) {
        if (numbers[i] == numbers[i + 1]) {
            duplication[0] = numbers[i];
            return true;
        }
    }
    return false;
}
② hash表
public boolean duplicate(int numbers[], int length, int[] duplication) {
    if (length <= 1) {
        return false;
    }
    HashMap<Integer, Integer> map = new HashMap<>();
    for (int i = 0; i < length; i++) {
        if (map.containsKey(numbers[i])) {
            duplication[0] = numbers[i];
            return true;
        }
        map.put(numbers[i], 1);
    }
    return false;
}
③ 元素交换
public boolean duplicate(int numbers[], int length, int[] duplication) {
    if (length <= 1) {
        return false;
    }
    for (int i = 0; i < length; i++) {
        // 第i个数不在第i个位置,不停的交换
        while (numbers[i] != i) {
            // 数值m与第m个位置的数相等,说明出现重复数字
            if (numbers[i] == numbers[numbers[i]]) {
                duplication[0] = numbers[i];
                return true;
            }
            // 不相等,将数值m放到第m个位置
            int temp = numbers[i];
            numbers[i] = numbers[temp];
            numbers[temp] = temp;
        }
    }
    return false;
}
2. 题目二:不修改数组找出重复的数字

在这里插入图片描述

  • 直接使用上面的hash表法,顺序遍历数组的同时,又能判断元素是否重复。
3. leetcode上的相似题 —— 136. 只出现一次的数字
  • hash表:先遍历数组,求得每个数字出现的次数;再遍历hash表,查找出现次数为1的数字。
  • 位操作(很简单): 因为 a ⊕ a = 0 , a ⊕ 0 = a a ⊕ a=0,a ⊕0=a aa=0a0=a,这里所有的元素都出现两次,除了只出现一次的数字,剩余元素做异或后都为0。
面试题4:二维数组中的查找

在这里插入图片描述

  • leetcode上的 240. 搜索二维矩阵 II
  • 矩阵中的元素按行升序,按例也是升序的,暴力查找效率不高。
  • 从右上角的元素开始进行比较,可以剔除行或者列,达到缩小搜索范围的效果。
public boolean Find(int target, int[][] array) {
    // 判断特殊情况,矩阵为空:没有行,有行但是没有列
    if (array.length == 0 || array[0].length == 0) {
        return false;
    }
    int row = 0, col = array[0].length - 1;
    boolean result = false;
    // 从右上角开始循环查找target,要求row小于矩阵的行数,col>=0
    while (row < array.length && col >= 0) {
        if (array[row][col] == target) {// 找到,更改result,退出循环
            result = true;
            break;
        } else if (array[row][col] > target) {
        // 右上角的数为当前列的最小值,如果该值大于target,剔除该列
            col--;
        } else {// 右上角的数为该行的最大值,如果该值小于target,剔除该行
            row++;
        }
    }
    return result;
}
面试题5:替换空格

在这里插入图片描述

① 不考虑原地替换
  • 遍历原来的字符串,遇到非空格字符,直接添加到结果字符串;否则,将%20添加到结果字符串。
  • 使用了StringBuffer.append()方法实现字符串的添加,StringBuffer.toString()方法实现类型的转换。
  • 注意: 无需考虑字符串长度为0的情况。
public String replaceSpace(StringBuffer str) {
    int len = str.length();
    StringBuffer result = new StringBuffer();
    for (int i = 0; i < len; i++) {
        if (str.charAt(i) == ' ') {
            result.append("%20");
        } else {
            String temp = str.charAt(i) + "";
            result.append(temp);
        }
    }
    return result.toString();
}
② 直接使用Java的API
  • 使用String.replace()方法,将字符串中的空格替换为%20。但是,运行效果貌似并不好。
public String replaceSpace(StringBuffer str) {
    String result=str.toString();
    return result.replace(" ","%20");
}
③ 使用双指针
  • 两次遍历,第一次根据字符串中的空格,对字符串进行扩充:在末尾添加空格;第二次遍历,从后往前,减少字符的移动次数。
  • 使用双指针,一个指向原字符串,一个用于指向扩充后的字符串。
public String replaceSpace(StringBuffer str) {
    // p指针,指向原字符串
    int p = str.length() - 1;
    // 首次遍历,扩充字符串,为添加%20留出空间
    for (int i = 0; i <= p; i++) {
        if (str.charAt(i) == ' ') {
            str.append("  ");
        }
    }
    // q指针,指向扩充后的字符串
    int q = str.length() - 1;
    // 从后往前遍历,减少移动次数
    while (p >= 0 && q>=p) {
        if (str.charAt(p) == ' ') { // 为空格,从后往前添加02%
            str.setCharAt(q--, '0');
            str.setCharAt(q--, '2');
            str.setCharAt(q--, '%');
        } else {// 直接添加字符
            str.setCharAt(q--, str.charAt(p));
        }
        p--;// p指针向前移动
    }
    return str.toString();
}
④ leetCode:88. Merge Sorted Array
  1. 由于合并后的数组还是存储在nums1中的,如果结束合并时nums1有剩余不用移动;如结束合并时nums2有剩余,需要移动到nums1中。
  2. 这里使用的是原地合并,如果借助ArrayList进行合并,可以从前往后合并。而且需要考虑nums1有剩余时,将剩余数字移动到list中。
  3. 两个有序链表的合并,也是借助新的链表头,也需要分别考虑两个链表不为未到末尾的情况。
public void merge(int[] nums1, int m, int[] nums2, int n) {
    // p指向扩充的nums1,i指向原始的nums1,j指向nums2
    int p = m + n - 1, i = m - 1, j = n - 1;
    while (i >= 0 && j >= 0) {
        if (nums1[i] > nums2[j]) {// nums1的当前数较大,移动到p位置
            nums1[p--] = nums1[i--];
        } else {// nums2的当前数较大,移动到p位置
            nums1[p--] = nums2[j--];
        }
    }
    // nums1还有剩余,不用移动,直接在原地就好
    // nums2有剩余,需要移动到nums1中弯沉合并
    while (j >= 0) {
        nums1[p--] = nums2[j--];
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值