Day2/7:2021-2-2-剑指哈希表整理+mysql【18-20】

6.哈希表

HashMap.getOrDefault(Object key, V defaultValue) 方法要记住。使用的次数还挺多。

剑指 Offer 50 .第一个只出现一次的字符

思考:不要理解错题意了。

在字符串 s 中找出第一个只出现一次的字符。对于aba,返回的结果应该为b。所以应该先遍历整个字符串s,统计每种字符的个数,然后再去遍历字符串,根据HashMap的结果去返回第一个只出现一次的字符。

我感觉计算字符出现的次数的思路还是挺常规的思路吧。

java.util.HashMap.getOrDefault(Object key, V defaultValue) 方法用于获取使用指定键映射的值。如果没有使用提供的键映射任何值,则返回默认值。

import java.util.HashMap;

public class Offer50 {
    public static void main(String[] args) {
        String s = new String("abaccdeff");
        System.out.println(firstUniqChar(s));
    }

    // 在字符串 s 中找出第一个只出现一次的字符。
    // 如果没有,返回一个单空格。 s 只包含小写字母。

    public static char firstUniqChar(String s) {
        // 输入条件判断,字符串s为空,则返回空格。
        if (s == null || s.length() == 0) {
            return ' ';
        }
        HashMap<Character, Integer> hashMap = new HashMap<>();
        for (int i = 0; i < s.length(); i++) {
            int count = hashMap.getOrDefault(s.charAt(i), 0) + 1;
            hashMap.put(s.charAt(i), count);
        }
        char res = ' ';
        for (int i = 0; i < s.length(); i++) {
            if (hashMap.get(s.charAt(i)) == 1) {
                res = s.charAt(i);
                break;
            }
        }
        return res;
    }
}
剑指 Offer 56 - I 数组中数字出现的次数

思考:

(1)普通解法,但是面试可能不能写这个做法
import java.util.HashMap;

public class Offer56_1 {
    public static void main(String[] args) {
        int[] nums = new int[]{1, 2, 10, 4, 1, 4, 3, 3};
        System.out.println(singleNumbers(nums));
    }

    // 一个整型数组 nums 里除两个数字之外,其他数字都出现了两次。
    // 请写程序找出这两个只出现一次的数字。
    public static int[] singleNumbers(int[] nums) {
        HashMap<Integer, Integer> map = new HashMap<>();
        for (int i = 0; i < nums.length; i++) {
            int count = map.getOrDefault(nums[i], 0) + 1;
            map.put(nums[i], count);
        }
        int[] res = new int[2];
        int index = 0;
        for (int i = 0; i < nums.length; i++) {
            if (map.get(nums[i]) == 1) {
                res[index++] = nums[i];
                if (index >= 2) {
                    break;
                }
            }
        }
        return res;
    }
}
(2)位运算的做法

位运算的做法,见题解,需要背诵。

题解:https://leetcode-cn.com/problems/shu-zu-zhong-shu-zi-chu-xian-de-ci-shu-lcof/solution/jian-zhi-offer-56-i-shu-zu-zhong-shu-zi-tykom/

image-20210130173526122

// 位运算
import java.util.Arrays;
import java.util.HashMap;

public class Offer56_1_2 {
    //一个整型数组 nums 里除两个数字之外,其他数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。
    public static void main(String[] args) {
        int[] nums = new int[]{4, 1, 4, 6};
        System.out.println(Arrays.toString(singleNumbers(nums)));
    }

    public static int[] singleNumbers(int[] nums) {
        //xor用来计算nums的异或和
        int xor = 0;

        // 计算异或和 并存到xor
        // e.g. [2,4,2,3,3,6] 异或和:(2^2)^(3^3)^(4^6)=2=010
        for (int num : nums) {
            xor ^= num;
//            System.out.println(Integer.toBinaryString(xor));
        }

        //设置mask为1,则二进制为0001
        // mask是一个二进制数,且其中只有一位是1,其他位全是0,比如000010,
        // 表示我们用倒数第二位作为分组标准,倒数第二位是0的数字分到一组,倒数第二位是1的分到另一组
        int mask = 1;

        // & operator只有1&1时等于1 其余等于0
        // 用上面的e.g. 4和6的二进制是不同的 我们从右到左找到第一个不同的位就可以分组 4=0100 6=0110
        // 根据e.g. 010 & 001 = 000 = 0则 mask=010
        // 010 & 010 != 0 所以mask=010
        // 之后就可以用mask来将数组里的两个数分区分开
        System.out.println("xor=" + Integer.toBinaryString(xor));
        System.out.println("mask=" + Integer.toBinaryString(mask));
        while ((xor & mask) == 0) {
            mask <<= 1;
            System.out.println(Integer.toBinaryString(mask));
        }
        System.out.println("mask=" + Integer.toBinaryString(mask));
        //两个只出现一次的数字
        int a = 0, b = 0;

        for (int num : nums) {
            //根据&是否为0区分将两个数字分区,并分别求异或和
            if ((num & mask) == 0) a ^= num;
            else {
                b ^= num;
            }
        }
        return new int[]{a, b};
    }
}
剑指 Offer 56 - II 数组中数字出现的次数 II

思考:

(1)简单做法 HashMap
import java.util.HashMap;

public class Offer56_2 {
    public static void main(String[] args) {
        int[] nums = new int[]{9, 1, 7, 9, 7, 9, 7};
        System.out.println(singleNumber(nums));
    }

    // 在一个数组 nums 中除一个数字只出现一次之外,其他数字都出现了三次。请找出那个只出现一次的数字。
    public static int singleNumber(int[] nums) {
        HashMap<Integer, Integer> map = new HashMap<>();
        for (int i = 0; i < nums.length; i++) {
            int count = map.getOrDefault(nums[i], 0) + 1;
            map.put(nums[i], count);
        }
        // 遍历 map 的 values
        int res = -1;
        for (Integer key : map.keySet()) {
            if (map.get(key) == 1) {
                res = key;
                break;
            }
        }
        return res;
    }
}
(2)

思考:

首先遍历一个数,将其转为二进制形式。数组形式。

比如 n=11=8+2+1=1011B

import java.util.Arrays;

public class Offer56_2_1 {
    public static void main(String[] args) {
        int n = 11;
        int[] count = new int[32];
        System.out.println("n=" + n + "二进制位:" + Integer.toBinaryString(n));
        for (int i = 0; i < 32; i++) {
            count[i] += n & 1;
            n >>>= 1;
            System.out.println("i=" + i + " count=" + Arrays.toString(count));
        }
    }
}
n=11二进制位:1011 你看,下面的结果是逆序的。这个是和自己一开始考虑的不一样哦。
i=0 count=[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
i=1 count=[1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
i=2 count=[1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
i=3 count=[1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
i=4 count=[1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
i=5 count=[1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

image-20210131152749876

image-20210131152810694

image-20210131152825407

public class Offer56_2 {
    public static void main(String[] args) {
        int[] nums = new int[]{9, 1, 7, 9, 7, 9, 7};
        System.out.println(singleNumber(nums));
    }

    public static int singleNumber(int[] nums) {
        int[] count = new int[32];
//        System.out.println(Arrays.toString(count));
        for (int i = 0; i < nums.length; i++) {
            for (int j = 0; j < 32; j++) {
                count[j] += nums[i] & 1;
                nums[i] >>>= 1;
//                System.out.println(Arrays.toString(count));
            }
        }
//        System.out.println(Arrays.toString(count));
        for (int i = 0; i < 32; i++) {
            count[i] = count[i] % 3;
        }
//        System.out.println(Arrays.toString(count));
        int res = 0;//[0,0,0,1]=0001
        for (int i = count.length - 1; i >= 0; i--) {
            res <<= 1;
            res |= count[i];
        }
        return res;
    }
}
剑指 Offer 57 - I 和为s的两个数字

思考:类型简单。根据字眼递增数组,这样就简单了。

输入一个递增排序的数组和一个数字s,在数组中查找两个数,使得它们的和正好是s。如果有多对数字的和等于s,则输出任意一对即可。

import java.util.Arrays;

public class Offer57 {
    public static void main(String[] args) {
        int[] nums = new int[]{2, 7, 11, 15};
        int target = 9;
        // Arrays.toString是为了将数组变为字符串去输出。
        System.out.println(Arrays.toString(twoSum(nums, target)));
    }

    // 输入一个递增排序的数组和一个数字s,在数组中查找两个数,使得它们的和正好是s。
    // 如果有多对数字的和等于s,则输出任意一对即可。
    public static int[] twoSum(int[] nums, int target) {
        // 1.扣字眼:递增排序的数组。
        int i = 0, j = nums.length - 1;
        while (i < j) {
            if (nums[i] + nums[j] == target) {
                break;
            } else if (nums[i] + nums[j] > target) {
                // j-- 会使得数据和 减少
                j--;
            } else if (nums[i] + nums[j] < target) {
                // i++ 会使得数据和 增加
                i++;
            }
        }
        return new int[]{nums[i], nums[j]};
    }
}
剑指 Offer 57 - II 和为s的连续正数序列 【需要重刷】

思考:官方认定是简单类型,但是我觉得并不简单吧。中等难度吧!

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class Offer57_2 {
    public static void main(String[] args) {
        int target = 15;
        // Arrays.toString是为了将数组变为字符串去输出。
        int[][] res = findContinuousSequence(target);
        for (int i = 0; i < res.length; i++) {
            System.out.println(Arrays.toString(res[i]));
        }
    }

    public static int[][] findContinuousSequence(int target) {
        int i = 1, j = 2, s = 3;
        List<int[]> res = new ArrayList<>();
        while (i < j) {
            if (s == target) {
                int[] ans = new int[j - i + 1];
                for (int k = i; k <= j; k++)
                    ans[k - i] = k;
                res.add(ans);
            }
            if (s > target) {
                s -= i;
                i++;
            } else if (s < target) {
                j++;
                s += j;
            }
        }
        return res.toArray(new int[0][]);
    }
}

第18章 全文本搜索

之前的表采用的InnoDB。本章使用全文本搜索,需要采用MyISAM的引擎。

productnotes 这个表是已经有的了。

18.2进行全文本搜索

# Match() 指定需要被搜索的列,against()指定搜索文本。
select note_text from productnotes where match(note_text) against('rabbit');

Customer complaint: rabbit has been able to detect trap, food apparently less effective now.
Quantity varies, sold by the sack load.All guaranteed to be bright and orange, and suitable for use as rabbit bait.

看下面标红的搜索结果,全文本搜索返回的结果能自动对结果进行排序。具有较高等级的行先返回。

Customer complaint: rabbit has been able to detect trap, food apparently less effective now.
Quantity varies, sold by the sack load.All guaranteed to be bright and orange, and suitable for use as rabbit bait.

image-20210201145247530

# 上面实现的内容搜索,也可以使用like语句完成。
select note_text from productnotes where note_text like '%rabbit%';

image-20210201145706303

18.2.2进行全文本搜索

SELECT note_text 
FROM productnotes 
WHERE MATCH(note_text) -- 指定要被搜索的列
AGAINST('rabbit'); -- 指定要搜索的内容

image-20210202115848930

# 下图中的例子 用来演示排序如何工作 

/*  注意:RANK (R)在mysql 8.0.2 (reserved)版本中为keyword保留字
当字段名与MySQL保留字冲突时,可以用字符‘’将字段名括起来
或者改为其他名字,比如as rank1等
*/
SELECT note_text, MATCH(note_text) AGAINST('rabbit') AS 'rank' FROM productnotes; 

image-20210202120638576

18.2.3使用查询扩展

 # 进行一个简单的全文本搜索,没有查询扩展

select note_text from productnotes where match(note_text) against('anvils');

image-20210202120903109

-- 和上面的代码是相同的搜索,不过这一次使用查询扩展
-- with query expansion 使用查询扩展
 select note_text from productnotes where match(note_text) against('anvils' with query expansion);

image-20210202120920102

18.2.4布尔文本搜索

-- 布尔文本搜索
-- 全文本布尔操作符 
#   布尔操作符       说明
#   +         包含,词必须存在 
#   -         排除,词必须不出现
#   >         包含,而且增加等级值 
#   <         包含,且减少等级值 
#   ()        把词组成子表达式(允许这些表达式作为一个组被包含、排除、排列等)
#   ~         取消一个词的排序值
#    *        词尾的通配符
#   “ ”       定义一个短语(与单个词的列表不一样,它匹配整个短语一边包含或排除这个短语)
# 全文本搜索检索包含词heavy的所有行

# 关键字IN BOOLEAN MODE,实际上没有指定布尔操作符,其结果与没有指定布尔方式的结果相同
select note_text from productnotes where match(note_text) against('heavy');
select note_text from productnotes where match(note_text) against('heavy' in boolean mode);

image-20210202122237112

上面图片的内容为:

Item is extremely heavy. Designed for dropping, not recommended for use with slings, ropes, pulleys, or tightropes.
Customer complaint: Not heavy enough to generate flying stars around head of victim. If being purchased for dropping, recommend ANV02 or ANV03 instead.

# -rope* 排除包含rope*(任何以rope开始的词,包括ropes)的行
#   -         排除,词必须不出现
#    *        词尾的通配符
select note_text from productnotes where match(note_text) against('heavy -rope*' in boolean mode);

上面图片的内容为:

Customer complaint: Not heavy enough to generate flying stars around head of victim. If being purchased for dropping, recommend ANV02 or ANV03 instead.

也就是去除了一条数据。

# 匹配包含词rabbit和bait的行
-- 是与运算。必须包含rabbit和bait这两条数据。
select note_text from productnotes where match(note_text) against('+rabbit +bait' in boolean mode);

Quantity varies, sold by the sack load.
All guaranteed to be bright and orange, and suitable for use as rabbit bait.

image-20210202153912242

# 不指定操作符,搜索匹配包含rabbit和bait中的至少一个词的行

select note_text from productnotes where match(note_text) against('rabbit bait' in boolean mode);

Quantity varies, sold by the sack load. All guaranteed to be bright and orange, and suitable for use as rabbit bait.
Customer complaint: rabbit has been able to detect trap, food apparently less effective now.

image-20210202153929246

# 搜索匹配短语rabbit bait而不是匹配两个词rabbit和bait。 
注意哦,这里的"rabbit bait"是指一个短语"rabbit bait"。
select note_text from productnotes where match(note_text) against('"rabbit bait"' in boolean mode);

Quantity varies, sold by the sack load.
All guaranteed to be bright and orange, and suitable for use as rabbit bait. rabbit bait是一个短语。

# 匹配rabbit和carrot,增加前者的等级,降低后者的等级
carrot 并没有出现吧。
select note_text from productnotes where match(note_text) against('>rabbit <carrot' in boolean mode);

Quantity varies, sold by the sack load. All guaranteed to be bright and orange, and suitable for use as rabbit bait.
Customer complaint: rabbit has been able to detect trap, food apparently less effective now.

# 必须匹配词 safe 和 combination ,降低后者的等级
这里的数据量太少了,不好找。
select note_text from productnotes where match(note_text) against('+safe +(<combination)' in boolean mode);

Safe is combination locked, combination not provided with safe. This is rarely a problem as safes are typically blown up or dropped by customers.

第19章 插入数据

19.1插入完整的行

# 插入一个新客户到customers表

# 简单但不安全,如果原来表列结构调整,会有问题 

insert into customers values (null,'Pep E. LaPew','100 Main Street','Los Angeles','CA','90046','USA',NULL,NULL);
# 表明括号内明确列名,更安全,稍繁琐 

insert into customers (cust_name,cust_address,cust_city,cust_state,cust_zip,cust_country,cust_contact,cust_email)
values ('Pep E. LaPew','100 Main Street','Los Angeles','CA','90046','USA',NULL,NULL);

– 插入多个行

# 方法1: 提交多个insert 语句

insert into customers(cust_name,cust_address,cust_city,cust_state,cust_zip,cust_country)
values('Pep E. LaPew','100 Main Street','Los Angeles','CA','90046','USA');
insert into customers(cust_name,cust_address,cust_city,cust_state,cust_zip,cust_country)
values('M. Martian','42 Galaxy Way','New York','NY','11213','USA');
# 方法2: 只要每条INSERT语句中的列名(和次序)相同,可以如下组合各语句

# 单条INSERT语句有多组值,每组值用一对圆括号括起来,用逗号分隔
# 使用逗号,插入多条数据。
insert into customers(cust_name,cust_address,cust_city,cust_state,cust_zip,cust_country)
values('Pep E. LaPew','100 Main Street','Los Angeles','CA','90046','USA'),('M. Martian','42 Galaxy Way','New York','NY','11213','USA');

19.4插入检索出来的数据

# 新建custnew表(非书本内容)
# 可以成功运行
CREATE TABLE `custnew` (
 `cust_id` int(11) NOT NULL AUTO_INCREMENT,
 `cust_name` char(50) NOT NULL,
 `cust_address` char(50) DEFAULT NULL,
 `cust_city` char(50) DEFAULT NULL,
 `cust_state` char(5) DEFAULT NULL,
 `cust_zip` char(10) DEFAULT NULL,
 `cust_country` char(50) DEFAULT NULL,
 `cust_contact` char(50) DEFAULT NULL,
 `cust_email` char(255) DEFAULT NULL,
 PRIMARY KEY (`cust_id`)
) ENGINE=InnoDB;
# 在表custnew中插入一行数据 (非书本内容)

insert into custnew (cust_id,cust_contact,cust_email,cust_name,cust_address,cust_city,cust_state,cust_zip,cust_country)
values(null,null,'mysql carsh course@learning.com','Y.CARY','BAKE WAY','NEW YORK','NY','112103','USA');
# 将custnew中内容插入到customers表中 

# 同书本代码不同,这里省略了custs_id,这样MySQL就会生成新值。

insert into customers (cust_contact,cust_email,cust_name,cust_address,cust_city,cust_state,cust_zip,cust_country)
select cust_contact,cust_email,cust_name,cust_address,cust_city,cust_state,cust_zip,cust_country from custnew;

第20章 更新和删除数据

20.1update语句 : 删除或更新指定列

# 更新: 客户10005现在有了电子邮件地址
where 用来限定客户是100005的数据行。
update customers set cust_email = 'elmer@fudd.com' where cust_id = 10005;
# 更新: 多个列 UPDATE+SET
UPDATE customers 
SET cust_name = 'The Fudds',
  cust_email = 'elmer@fudd.com'
WHERE cust_id = 10005;
# 删除: 某个列的值,可设置它为NULL(假如表定义允许NULL值)
update + set
update customers set cust_email = null where cust_id = 10005;
-- delete +where  语句: 删除整行而不是某列 
# 从customers表中删除一行
delete from customers where cust_id = 10006;
-- truncate table语句 
# 如果想从表中删除 所有行,不要使用DELETE,可使用TRUNCATE TABLE语句
# TRUNCATE实际是删除原来的表并重新创建一个表,而不是逐行删除表中的数据
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值