ARTS-8(坚持不容易,但还是想试试)

Algorithm

leecode61-旋转链表
题目描述
给定一个链表,旋转链表,将链表每个节点向右移动 k 个位置,其中 k 是非负数。
示例 1:
输入: 1->2->3->4->5->NULL, k = 2
输出: 4->5->1->2->3->NULL
解释:
向右旋转 1 步: 5->1->2->3->4->NULL
向右旋转 2 步: 4->5->1->2->3->NULL
示例 2:
输入: 0->1->2->NULL, k = 4
输出: 2->0->1->NULL
解释:
向右旋转 1 步: 2->0->1->NULL
向右旋转 2 步: 1->2->0->NULL
向右旋转 3 步: 0->1->2->NULL
向右旋转 4 步: 2->0->1->NULL

解题思路
1、先将链表闭合成环
2、找到相应的位置断开这个环,确定新的链表头和链表尾,经观察可以发现新的链表头在位置为n-k处,其中n是链表中点的个数,新的链表尾位于位置n-k-1;
其中k<n或者k>=n的时候,k的取值都可以考虑为k=(k/n)*n+k%n
3、找到旧的尾部并将其与链表头相连,tail.next=head,此时链表闭合成环,同时计算出链表的长度
4、找到新的尾部,第(n-k%n-1)个节点,新的链表头为第(n-k%n)个节点
5、断开new_tail=None,并返回新的链表头

class Solution{
	public ListNode rotateRight(ListNode head, int k) {
	if(head==null) return null;
	if(head.next==null) return null;
	ListNode tail = head;
	for(n = 1; tail.next != null; n++){
		tail=tail.next;
		tail.next=head;
		}
	ListNode new_tail=head;
	for (int i = 0; i < n - k % n - 1; i++){
		new_tail=new_tail.next;
		ListNode new_head = new_tail.next;
		}
	new_tail.next = null;
	return new_head;
	}
}

Review

【转】
获取数据库的相关信息:
1.获得数据库的一些相关信息
2.获得该用户下面的所有表
3.获得该用户下面的所有视图
4.获得数据库中所有方案名称
5.获得表或视图中的所有列信息
6. 获得一个表的索引信息
7.获得一个表的主键信息
8.获得一个表的外键信息
[DatabaseMetaData的用法](https://www.cnblogs.com/shide/p/3340906.html)
[Java中DatabaseMetaData 元数据信息](https://www.cnblogs.com/chenying99/archive/2012/08/17/2644500.html)

项目中实践介绍

1、获取数据库中的表

/**
     * 获取数据库的表
     * @param dbType  数据库类型mysql 、oracle、db2
     * @param url     连接串
     * @param userName   用户名
     * @param pwd   用户密码
     * @param excluedSchemes  数据库的系统表
     * @return
     */
    public static List<TableMeta> getAllTables(String dbType, String url, String userName, String pwd, String[] types, List<String> excluedSchemes) throws ClassNotFoundException, SQLException {
        String driverName = JDBC_DRIVER_NAME.get(dbType.toLowerCase());

        Class.forName(driverName);
        List<TableMeta> tables = new ArrayList<>();
        try (Connection  connection = DriverManager.getConnection(url, userName, pwd)) {
            DatabaseMetaData metaData = connection.getMetaData();
           // String schema = null;
            String catalog = null;
            if("mysql".equals(dbType.toLowerCase())){
                catalog = selectSchema(connection);
            }

            //表
            ResultSet rs = metaData.getTables(catalog, null, null, types);
            while(rs.next()){
                TableMeta tableMeta = new TableMeta();
                if(StringUtils.isBlank(rs.getString("TABLE_SCHEM")) ){
                    tableMeta.setName(rs.getString("TABLE_NAME"));
                }else{
                    if(excluedSchemes.contains(rs.getString("TABLE_SCHEM").toUpperCase())){
                        continue;
                    }
                    tableMeta.setName(rs.getString("TABLE_SCHEM") + "." + rs.getString("TABLE_NAME"));
                }
                tableMeta.setType(rs.getString("TABLE_TYPE"));
                tables.add(tableMeta);
            }
            rs.close();
        }
        return tables;
    }
//选择当前数据库
private static String selectSchema(Connection connection) throws SQLException {
        try(Statement st = connection.createStatement();
        ResultSet rs = st.executeQuery("select database()")){
            while(rs.next()){
                return rs.getString(1);
            }
        }
        return null;
    }

2、获取数据库字段信息

/**
     * 指定数据库用户名,密码获取数据库表名,字段名,字段类型,长度(精度),该字段是否是主键
     * @param dbType 数据库类型
     * @param url   连接串
     * @param userName  用户名
     * @param pwd   用户密码
     * @return
     * @throws Exception
     */
    public static List<ColumnMeta> getAllTableColumns(String dbType, String url, String userName, String pwd, String schema, String tableName) throws ClassNotFoundException, SQLException {
        String driverName = JDBC_DRIVER_NAME.get(dbType.toLowerCase());

        Class.forName(driverName);
        List<ColumnMeta> columns = new ArrayList<>();
        try (Connection  connection = DriverManager.getConnection(url, userName, pwd)){
            DatabaseMetaData metaData = connection.getMetaData();
            String catalog = null;
            if("mysql".equals(dbType.toLowerCase())){
                catalog = selectSchema(connection);
            }
            ResultSet rs = metaData.getPrimaryKeys(catalog, schema, tableName);
            Set<String> primaryKeys = new TreeSet<>();
            while(rs.next()){
                primaryKeys.add(rs.getString("COLUMN_NAME"));
            }
            rs.close();
            //列源数据信息
            rs = metaData.getColumns(catalog, schema, tableName, null);

           // System.out.println(rs.getMetaData());
            while(rs.next()){
                ColumnMeta columnMeta = new ColumnMeta();
                columnMeta.setName(rs.getString("COLUMN_NAME"));
                columnMeta.setType(rs.getString("TYPE_NAME"));
                if("oracle".equals(dbType.toLowerCase()) && "NUMBER".equals(rs.getString("TYPE_NAME"))){
                    columnMeta.setLength(rs.getInt("CHAR_OCTET_LENGTH"));
                }else{
                    columnMeta.setLength(rs.getInt("COLUMN_SIZE"));
                }

                columnMeta.setNullable(rs.getInt("NULLABLE") == 1);
                columnMeta.setScale(rs.getInt("DECIMAL_DIGITS"));
                //字段类型是字符串,小数点字段null
                if(!columnMeta.getType().toLowerCase().contains("decimal")){
                    columnMeta.setScale(null);
                }
                columnMeta.setComment(rs.getString("REMARKS"));
                columnMeta.setPrimaryKey(primaryKeys.contains(columnMeta.getName()));
                columns.add(columnMeta);
            }
            rs.close();
        }
        return columns;
    }

3、获取表的主键信息

    public static Pair<String, List<Pair<String, Integer>>> getPrimaryKeys(Connection targetConn, String catalog, String schema, String targetTable) throws SQLException {
        try(ResultSet rs = targetConn.getMetaData().getPrimaryKeys(catalog, schema, targetTable)){
            String pkName = null;
            List<Pair<String, Integer>> primaryKeys = new ArrayList<>();
            while(rs.next()){
                primaryKeys.add(Pair.of(rs.getString("COLUMN_NAME"), rs.getInt("KEY_SEQ")));
                pkName = rs.getString("PK_NAME");
            }
            primaryKeys.sort(Comparator.comparing(Pair::getRight));
            return Pair.of(pkName, primaryKeys);
        }

    }
//创建主键
                Pair<String, List<Pair<String, Integer>>> keys = DBUtils.getPrimaryKeys(targetConn, null, scheme, tableName);
if(!keys.getRight().isEmpty()){
	String keySql = "ALTER TABLE "+tempTable+" ADD constraint PK_ID primary key ("+StringUtils.join(keys.getRight().stream().map(e->e.getKey()).collect(Collectors.toList()),",")+")";
	logger.info("添加主键约束{}", keySql);
	statement.execute(keySql);
}

4、获取索引信息
每个索引列描述都有以下列:

  • TABLE_CAT String => 表类别(可为 null)
  • TABLE_SCHEM String => 表模式(可为 null)
  • TABLE_NAME String => 表名称
  • NON_UNIQUE boolean => 索引值是否可以不唯一。TYPE 为 tableIndexStatistic 时索引值为 false
  • INDEX_QUALIFIER String => 索引类别(可为 null);TYPE 为 tableIndexStatistic 时索引类别为 null
  • INDEX_NAME String => 索引名称;TYPE 为 tableIndexStatistic 时索引名称为 null
  • TYPE short => 索引类型:
    tableIndexStatistic - 此标识与表的索引描述一起返回的表统计信息
    tableIndexClustered - 此为集群索引
    tableIndexHashed - 此为散列索引
    tableIndexOther - 此为某种其他样式的索引
  • ORDINAL_POSITION short => 索引中的列序列号;TYPE 为 tableIndexStatistic 时该序列号为零
  • COLUMN_NAME String => 列名称;TYPE 为 tableIndexStatistic 时列名称为 null
  • ASC_OR_DESC String => 列排序序列,“A” => 升序,“D” => 降序,如果排序序列不受支持,可能为 null;TYPE 为 tableIndexStatistic 时排序序列为 null
  • CARDINALITY int => TYPE 为 tableIndexStatistic 时,它是表中的行数;否则,它是索引中唯一值的数量。
  • PAGES int => TYPE 为 tableIndexStatisic 时,它是用于表的页数,否则它是用于当前索引的页数。
  • FILTER_CONDITION String => 过滤器条件,如果有的话。(可能为 null)
public static List<TableIndex> getIndexs(Connection targetConn, String catalog, String schema, String targetTable) throws SQLException {
        try(ResultSet rs = targetConn.getMetaData().getIndexInfo(catalog, schema, targetTable, false, false)){
            Map<String, TableIndex> indexs = new HashMap<>();
            while(rs.next()){
                String indexName = rs.getString("INDEX_NAME");
                if(indexName == null){
                    continue;
                }
                TableIndex tableIndex = indexs.get(indexName);
                if(tableIndex == null){
                    tableIndex = new TableIndex();
                    indexs.put(indexName, tableIndex);
                    tableIndex.setIndexName(indexName);
                    tableIndex.setColumns(new ArrayList<>());
                    tableIndex.setIndexCatalog(rs.getString("INDEX_QUALIFIER"));
                    tableIndex.setNonUnqiue(rs.getBoolean("NON_UNIQUE"));
                    tableIndex.setType(rs.getShort("TYPE"));
                    tableIndex.setIndexName(indexName);
                }
                IndexColumn indexColumn = new IndexColumn();
                indexColumn.setColumnName(rs.getString("COLUMN_NAME"));
                indexColumn.setColumnIndex(rs.getShort("ORDINAL_POSITION"));
                indexColumn.setAscOrDsc(rs.getString("ASC_OR_DESC"));
                tableIndex.getColumns().add(indexColumn);
            }
            for(TableIndex tableIndex : indexs.values()){
                tableIndex.getColumns().sort(Comparator.comparing(IndexColumn::getColumnIndex));
            }
            return indexs.values().stream().collect(Collectors.toList());
        }
    }

5、获取权限信息

resultset gettableprivileges(string catalog,
                             string schemapattern,
                             string tablenamepattern)
                             throws sqlexception

获取可在类别中使用的每个表的访问权的描述。注意,表特权可用于表中的一个或多个列。仅返回与模式和表名称标准匹配的特权。它们根据 table_cat、table_schem、table_name 和 privilege 进行排序。
返回值:
每个特权描述都有以下列:

  • table_cat string => 表类别(可为 null)
  • table_schem string => 表模式(可为 null)
  • table_name string => 表名称
  • grantor string => 访问权的授权人(可为 null)
  • grantee string => 访问权的被授权人
  • privilege string => 访问权的名称(select、insert、update、refrences 等)
  • is_grantable string => 如果允许被授权人将权利授予他人,则为 “yes”;如果不允许,则为 “no”;如果未知,则为 null

参数:
catalog - 类别名称;它必须与存储在数据库中的类别名称匹配;该参数为 “” 表示获取没有类别的那些描述;为 null 则表示该类别名称不应该用于缩小搜索范围
schemapattern - 模式名称的模式;它必须与存储在数据库中的模式名称匹配;该参数为 “” 表示获取没有模式的那些描述;为 null 则表示该模式名称不应该用于缩小搜索范围
tablenamepattern - 表名称模式;它必须与存储在数据库中的表名称匹配

public static boolean canDropTable(Connection conn, String catalog, String scheme, String targetTable) throws SQLException {

        try(ResultSet rs = conn.getMetaData().getTablePrivileges(catalog, scheme, targetTable)){
            List<String> privileges = new ArrayList<>();
            privileges.add("DROP");
            privileges.add("ALTER");
            privileges.add("CREATE");
            while(rs.next()){
                String privilege = rs.getString("PRIVILEGE");
                if("CONTROL".equals(privilege)){
                    return true;
                }
                if(privileges.contains(privilege)){
                    privileges.remove(privilege);
                }
            }
            return privileges.isEmpty();
        }
    }

Tips

1、Mysql权限

mysql中存在4个控制权限的表,分别为user表,db表,tables_priv表,columns_priv表
mysql权限表的验证过程为:
1.先从user表中的Host,User,Password这3个字段中判断连接的ip、用户名、密码是否存在,存在则通过验证。
2.通过身份认证后,进行权限分配,按照user,db,tables_priv,columns_priv的顺序进行验证。即先检查全局权限表 user,如果user中对应的权限为Y,则此用户对所有数据库的权限都为Y,将不再检查db, tables_priv,columns_priv;如果为N,则到db表中检查此用户对应的具体数据库,并得到db中为Y的权限;如果db中为N,则检 查tables_priv中此数据库对应的具体表,取得表中的权限Y,以此类推。
【转】
Mysql权限速查表以及权限详解
mysql用户权限管理

2、StringUtils.join()方法的方法和使用
StringUtils.join()和String.join()用途:将数组或集合以某拼接符拼接到一起形成新的字符串。

Pair<String, List<Pair<String, Integer>>> keys;
StringUtils.join(keys.getRight().stream().map(e->e.getKey()).collect(Collectors.toList()), ",")

3、Map和Pair的区别
Pair实现了Map.Entry 主要方法就是 getKey、getValue。对应着Pair中的Left、Right。
一般调用都使用 of方法,返回一个ImmutablePair不可变的子类,另外有可变的子类MutablePair。
pair保存的是一对key value,而map可以保存多对key value

import com.alibaba.fastjson.JSONObject;
import javafx.util.Pair;
import java.util.*;
import java.util.stream.Collectors;

public class App {
    public static void main(String[] args) {
        //为了代码可以运行,完善了此段代码。
        //首先创建3个JSONObject对象,并加入topList
        JSONObject json1 = new JSONObject();
        json1.put("a", 9);
        JSONObject json2 = new JSONObject();
        json2.put("a", 4);
        JSONObject json3 = new JSONObject();
        json3.put("a", 7);
        JSONObject json4 = new JSONObject();
        json4.put("a", 8);
        List<Pair<Integer, JSONObject>> topList = new ArrayList<Pair<Integer, JSONObject>>();
        topList.add(new Pair<>(1, json1));
        topList.add(new Pair<>(2, json2));
        topList.add(new Pair<>(3, json3));
        topList.add(new Pair<>(4, json4));

        //为了对topList依据JSONObject的值进行排序,重写了Comparator,事实上用Lambda写更简单
        Collections.sort(topList, new Comparator<Pair<Integer, JSONObject>>() {
            @Override
            public int compare(Pair<Integer, JSONObject> o1, Pair<Integer, JSONObject> o2) {
                //这里想使用JSONObject的值来进行排序
                return o2.getValue().getIntValue("a") - o1.getValue().getIntValue("a");
            }
        });
        //输出排序结果
        topList.stream().forEach((pair) -> System.out.println(pair));

        System.out.println("=======================");

        //如果用Map来做同样的事情,会发现由于Map中的Key和Value存储在EntrySet中,导致sort方法没有办法实现
        //如果是对Key进行排序可以使用TreeMap,但是对Value进行排序就只能自己实现
        Map<Integer, JSONObject> mapList = new LinkedHashMap<>();
        mapList.put(1, json1);
        mapList.put(2, json2);
        mapList.put(3, json3);
        mapList.put(4, json4);

        //只能先排序,然后收集到一个List中
        List<Map.Entry<Integer, JSONObject>> sortedList = mapList.entrySet()
                .stream()
                .sorted(((o1, o2) -> o2.getValue().getIntValue("a") - o1.getValue().getIntValue("a")))
                .collect(Collectors.toList());

        //把排序好的再导入Map中
        mapList.clear();
        sortedList.stream().forEach(entry -> mapList.put(entry.getKey(), entry.getValue()));
        //输出排序结果
        mapList.entrySet().stream().forEach(entry -> System.out.println(entry));
    }
}

由于Map中使用Entry来存放Key和Value,又由于Map使用EntrySet来提供对外接口,导致直接对Map中的Value进行排序不方便。因此你看到有人直接使用List来存储Pair<Key,Value>,这样的话对Value进行排序就很方便了。如果只需要对Key排序的话,使用TreeMap更好。

Share

坚持和他一起写ARTS,在一起要双倍快乐,也要双倍进步。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值